io 流主要提供四个接口
InputStream OutputStream Reader Writer
InputStream 输入字节流,关注字节的读取,io 包提供如下 InputStream 的实现
ByteArrayInputStream FileInputStream PipedInputStream DataInputStream ObjectInputStream BufferedInputStream SequenceInputStream PushbackInputStream
InputStream 提供如下接口:
read read(buffer) read(buffer, offset, length) readNBytes(buffer, offset, length) readAllBytes skip available mark reset close
{
InputStream in = new ByteArrayInputStream("0123456789".getBytes());
assertEquals(in.read(), '0');
}
{
InputStream in = new ByteArrayInputStream("0123456789".getBytes());
byte[] buf = new byte[4];
assertEquals(in.read(buf), 4);
assertArrayEquals(buf, "0123".getBytes());
}
{
InputStream in = new ByteArrayInputStream("0123456789".getBytes());
byte[] buf = new byte[20];
assertEquals(in.read(buf), 10);
assertArrayEquals(Arrays.copyOf(buf, 10), "0123456789".getBytes());
}
{
InputStream in = new ByteArrayInputStream("0123456789".getBytes());
byte[] buf = new byte[20];
assertEquals(in.read(buf, 1, 4), 4);
assertArrayEquals(Arrays.copyOfRange(buf, 1, 1 + 4), "0123".getBytes());
}
{
InputStream in = new ByteArrayInputStream("0123456789".getBytes());
byte[] buf = new byte[20];
assertEquals(in.readNBytes(buf, 1, 4), 4);
assertArrayEquals(Arrays.copyOfRange(buf, 1, 1 + 4), "0123".getBytes());
}
{
InputStream in = new ByteArrayInputStream("0123456789".getBytes());
assertArrayEquals(in.readAllBytes(), "0123456789".getBytes());
}
{
InputStream in = new ByteArrayInputStream("0123456789".getBytes());
assertEquals(in.skip(2), 2);
assertEquals(in.available(), 8);
assertEquals(in.read(), '2');
assertEquals(in.available(), 7);
in.mark(0);
assertEquals(in.read(), '3');
in.reset();
assertEquals(in.available(), 7);
assertEquals(in.read(), '3');
in.close();
}
{
InputStream in = new ByteArrayInputStream("0123456789".getBytes());
for (int ch = in.read(); ch != -1; ch = in.read()) {
System.out.println(ch);
}
}
OutputStream 输出字节流,关注字节的写入,io 包提供了如下 OutputStream 的实现
ByteArrayOutputStream FileOutputStream PipedOutputStream DataOutputStream ObjectOutputStream BufferedOutputStream SequenceOutputStream
OutputStream 提供如下接口:
write write(buffer) write(buffer, offset, length) flush close
OutputStream out = new ByteArrayOutputStream();
out.write('0');
out.write("123456789".getBytes());
out.write("0123456789".getBytes(), 1, 2);
out.flush();
out.close();
Reader 字符输入流,关注字符的读取,io 包提供如下 Reader 的实现
CharArrayReader : 字符数组输入流 FileReader : 文件字符输入流 PipedReader : 管道输入流,可以和 PipedWriter 连接,通常用于线程间通信 StringReader : 字符串输入流 BufferedReader : 带缓冲 buffer 的字符输入流 LineNumberReader : 带行号的字符输入流 PushbackReader : 能回退的字符输入流 InputStreamReader : 输入字节流转字符流 Reader 提供如下接口:
read read(buffer) read(buffer, offset, length) read(CharBuffer skip mark reset close
{
Reader reader = new CharArrayReader("0123456789".toCharArray());
assertEquals(reader.read(), '0');
}
{
Reader reader = new CharArrayReader("0123456789".toCharArray());
char[] buf = new char[4];
assertEquals(reader.read(buf), 4);
assertArrayEquals(buf, "0123".toCharArray());
}
{
Reader reader = new CharArrayReader("0123456789".toCharArray());
char[] buf = new char[20];
assertEquals(reader.read(buf), 10);
assertArrayEquals(Arrays.copyOf(buf, 10), "0123456789".toCharArray());
}
{
Reader reader = new CharArrayReader("0123456789".toCharArray());
char[] buf = new char[20];
assertEquals(reader.read(buf, 1, 4), 4);
assertArrayEquals(Arrays.copyOfRange(buf, 1, 1 + 4), "0123".toCharArray());
}
{
Reader reader = new CharArrayReader("0123456789".toCharArray());
CharBuffer buf = CharBuffer.allocate(20);
assertEquals(reader.read(buf), 10);
}
{
Reader reader = new CharArrayReader("0123456789".toCharArray());
assertTrue(reader.ready());
assertEquals(reader.skip(2), 2);
assertEquals(reader.read(), '2');
reader.mark(0);
assertEquals(reader.read(), '3');
reader.reset();
assertEquals(reader.read(), '3');
reader.close();
}
{
Reader reader = new CharArrayReader("0123456789".toCharArray());
for (int ch = reader.read(); ch != -1; ch = reader.read()) {
System.out.println(ch);
}
}
Writer 字符输出流,关注字符的写入,io 包提供如下 Writer 的实现
CharArrayWriter : 字符数组输出流 FileWriter : 文件字符输出流 PipedWriter : 管道输出流,可以和 PipedReader 连接,通常用于线程间通信 StringWriter : 字符串输出流 BufferedWriter : 带缓冲 buffer 的字符输出流 OutputStreamWriter : 输出字节流转字符流 Writer 提供如下接口:
write(char) write(string) write(string, offset, length) write(char[]) write(char[], offset, length) append(ch) append(CharSequence) append(CharSequence, offset, length) flush close
Writer writer = new CharArrayWriter();
writer.write('0');
writer.write("0123456789");
writer.write("0123456789", 1, 4);
writer.write("0123456789".toCharArray());
writer.write("0123456789".toCharArray(), 1, 4);
writer.append('0');
writer.append(new StringBuilder("0123456789"));
writer.append(new StringBuilder("0123456789"), 1, 4);
writer.flush();
writer.close();
文件字节流关注文件的读取和写入
{
FileOutputStream fout = new FileOutputStream("/tmp/test.txt");
fout.write("No patient who, who has no wisdom".getBytes());
fout.close();
}
{
FileInputStream fin = new FileInputStream("/tmp/test.txt");
assertArrayEquals(fin.readAllBytes(), "No patient who, who has no wisdom".getBytes());
fin.close();
}
缓冲字节流采用装饰者模式,装饰在其他流上,使流拥有了缓存功能,从而提高读写了效率
{
BufferedOutputStream bout = new BufferedOutputStream(new FileOutputStream("/tmp/test.txt"));
bout.write("People lack the willpower, rather than strength".getBytes());
bout.close();
}
{
BufferedInputStream bin = new BufferedInputStream(new FileInputStream("/tmp/test.txt"));
assertArrayEquals(bin.readAllBytes(), "People lack the willpower, rather than strength".getBytes());
bin.close();
}
二进制字节流关注在基本数据类型的读取和写入,采用装饰者模式,能装饰在其他流上
DataOutputStream 在 OutputStream 的基础上新增了如下接口:
writeBoolean writeByte writeShort writeInt writeLong writeFloat writeDouble writeChar writeUTF
DataInputStream 在 InputStream 的基础上新增了如下接口:
readBoolean readByte readShort readInt readLong readFloat readDouble readChar readUTF
{
DataOutputStream dout = new DataOutputStream(new BufferedOutputStream(new FileOutputStream("/tmp/test.txt")));
dout.writeBoolean(false);
dout.writeByte('x');
dout.writeShort(123);
dout.writeInt(123456);
dout.writeLong(123456789);
dout.writeFloat((float) 123.456);
dout.writeDouble(123.456);
dout.writeUTF("Rome wasn’t built in one day");
dout.close();
}
{
DataInputStream din = new DataInputStream(new BufferedInputStream(new FileInputStream("/tmp/test.txt")));
assertEquals(din.readBoolean(), false);
assertEquals(din.readByte(), 'x');
assertEquals(din.readShort(), 123);
assertEquals(din.readInt(), 123456);
assertEquals(din.readLong(), 123456789);
assertEquals(din.readFloat(), (float) 123.456);
assertEquals(din.readDouble(), 123.456);
assertEquals(din.readUTF(), "Rome wasn’t built in one day");
din.close();
}
对象字节流关注对象的写入和读取,同时拥有二进制字节流的所有功能,同样采用装饰者模式
ObjectOutputStream 相比 DataOutputStream 新增了如下接口:
writeObject : 写入任何 Serializable 对象 ObjectInputStream 相比 DataInputStream 新增了如下接口:
readObject : 从流中读取一个对象 {
ObjectOutputStream oout = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream("/tmp/test.txt")));
oout.writeBoolean(false);
oout.writeByte('x');
oout.writeShort(123);
oout.writeInt(123456);
oout.writeLong(123456789);
oout.writeFloat((float) 123.456);
oout.writeDouble(123.456);
oout.writeUTF("Nothing is impossible to a willing heart");
oout.writeObject(new Point(123, 456));
oout.close();
}
{
ObjectInputStream oin = new ObjectInputStream(new BufferedInputStream(new FileInputStream("/tmp/test.txt")));
assertEquals(oin.readBoolean(), false);
assertEquals(oin.readByte(), 'x');
assertEquals(oin.readShort(), 123);
assertEquals(oin.readInt(), 123456);
assertEquals(oin.readLong(), 123456789);
assertEquals(oin.readFloat(), (float) 123.456);
assertEquals(oin.readDouble(), 123.456);
assertEquals(oin.readUTF(), "Nothing is impossible to a willing heart");
Point point = (Point) oin.readObject();
assertEquals(point.x, 123);
assertEquals(point.y, 456);
oin.close();
}
可回退字节流内部维护了一个固定大小的缓冲区(可通过构造函数配置 buffer 的大小),允许将字节回退到缓冲区,如果超过了缓冲区大小,会抛出异常
PushbackInputStream 在 InputStream 的基础上新增了如下接口:
unread unread(buffer) unread(buffer, offset, length)
PushbackInputStream pin = new PushbackInputStream(new ByteArrayInputStream("Failure is the mother of success".getBytes()), 10);
byte[] buf = new byte[7];
assertEquals(pin.read(buf), 7);
assertArrayEquals(buf, "Failure".getBytes());
pin.unread(buf);
assertEquals(pin.read(buf), 7);
assertArrayEquals(buf, "Failure".getBytes());
// 超过 buffer 的大小,抛出 IOException
assertThrows(IOException.class, () -> pin.unread("01234567890".getBytes()));
SequenceInputStream 将多个 InputStream 合并成一个
InputStream in1 = new ByteArrayInputStream("For man is man and master of his fate/n".getBytes());
InputStream in2 = new ByteArrayInputStream("Cease to struggle and you cease to live/n".getBytes());
Vector<InputStream> vi = new Vector<>(List.of(in1, in2));
SequenceInputStream sin = new SequenceInputStream(vi.elements());
assertArrayEquals(sin.readAllBytes(), "For man is man and master of his fate/nCease to struggle and you cease to live/n".getBytes());
PipedInputStream 和 PipedOutputStream 通过调用 connect 方法建立连接,往 PipedOutputStream 写入,能从 PipedInputStream 读取,这种管道模式是一对一的,对一个管道流建立两次连接会抛出异常
PipedOutputStream 在 OutputStream 的基础上提供如下接口:
connect : 与一个 PipedInputStream 建立连接,如果已经建立连接,将抛出异常 PipedInputStream 在 InputStream 的基础上提供如下接口:
connect : 与一个 PipedOutputStream 建立连接,如果已经建立连接,将抛出异常 ExecutorService es = Executors.newCachedThreadPool();
PipedInputStream pin = new PipedInputStream();
PipedOutputStream pout = new PipedOutputStream();
pin.connect(pout);
es.execute(() -> {
try {
ObjectOutputStream oout = new ObjectOutputStream(pout);
oout.writeInt(123456);
oout.writeUTF("如果你还没能找到让自己热爱的事业,继续寻找,不要放弃");
oout.close();
} catch (IOException e) {
e.printStackTrace();
}
});
es.execute(() -> {
try {
ObjectInputStream oin = new ObjectInputStream(pin);
assertEquals(oin.readInt(), 123456);
assertEquals(oin.readUTF(), "如果你还没能找到让自己热爱的事业,继续寻找,不要放弃");
oin.close();
} catch (IOException e) {
e.printStackTrace();
}
});
try {
es.shutdown();
while (!es.awaitTermination(1000, TimeUnit.MILLISECONDS)) {
// nothing to do
}
} catch (Exception e) {
e.printStackTrace();
}
文件字符流关注文件的读取和写入,使用默认的 utf-8 来编码
{
FileWriter fw = new FileWriter("/tmp/test.txt");
assertEquals(fw.getEncoding(), "UTF8");
System.out.println(fw.getEncoding());
fw.write("初学者的心态;拥有初学者的心态是件了不起的事情");
fw.flush();
fw.close();
}
{
FileReader fr = new FileReader("/tmp/test.txt");
assertEquals(fr.getEncoding(), "UTF8");
StringBuilder sb = new StringBuilder();
for (int ch = fr.read(); ch != -1; ch = fr.read()) {
sb.append((char) ch);
}
assertEquals(sb.toString(), "初学者的心态;拥有初学者的心态是件了不起的事情");
fr.close();
}
采用装饰者模式,装饰在其他字符流上,增加缓存功能,提高读写性能。 Files 提供了缓冲字符流的构造,可以指定编码
BufferedWriter 在 Writer 的基础上,新增了如下接口:
newLine : 写入一个换行符 BufferedReader 在 Reader 的基础上,新增了如下接口:
readLine : 读取一个行,如果没有新的行,返回 null lines : 返回一个 java.util.stream.Stream ,支持 java 8 的流式处理 {
// BufferedWriter bw = new BufferedWriter(new FileWriter("/tmp/test.txt"));
BufferedWriter bw = Files.newBufferedWriter(Paths.get("/tmp/test.txt"), Charsets.UTF_8);
bw.write("穷则独善其身,达则兼济天下");
bw.newLine();
bw.write("玉不琢、不成器,人不学、不知义");
bw.newLine();
bw.close();
}
{
// BufferedReader br = new BufferedReader(new FileReader("/tmp/test.txt"));
BufferedReader br = Files.newBufferedReader(Paths.get("/tmp/test.txt"), Charsets.UTF_8);
assertEquals(br.readLine(), "穷则独善其身,达则兼济天下");
assertEquals(br.readLine(), "玉不琢、不成器,人不学、不知义");
assertEquals(br.readLine(), null);
br.close();
}
{
// BufferedReader br = new BufferedReader(new FileReader("/tmp/test.txt"));
BufferedReader br = Files.newBufferedReader(Paths.get("/tmp/test.txt"), Charsets.UTF_8);
assertThat(br.lines().collect(Collectors.toList()), equalTo(List.of(
"穷则独善其身,达则兼济天下",
"玉不琢、不成器,人不学、不知义"
)));
br.close();
}
InputStreamReader 和 OutputStreamWriter 能将字节流转化字符流,还可以指定编码
{
OutputStreamWriter ow = new OutputStreamWriter(new FileOutputStream("/tmp/test.txt"), "utf-8");
ow.write("你究竟是想一辈子卖糖水,还是希望获得改变世界的机遇");
ow.flush();
ow.close();
}
{
InputStreamReader rw = new InputStreamReader(new FileInputStream("/tmp/test.txt"), "utf-8");
StringBuilder sb = new StringBuilder();
for (int ch = rw.read(); ch != -1; ch = rw.read()) {
sb.append((char) ch);
}
assertEquals(sb.toString(), "你究竟是想一辈子卖糖水,还是希望获得改变世界的机遇");
rw.close();
}
字符串构建的流
{
StringWriter sw = new StringWriter();
sw.write("学而不思则罔,思而不学则殆");
assertEquals(sw.getBuffer().toString(), "学而不思则罔,思而不学则殆");
sw.close();
}
{
StringReader sr = new StringReader("一年之计在于春,一日之计在于晨");
StringBuilder sb = new StringBuilder();
for (int ch = sr.read(); ch != -1; ch = sr.read()) {
sb.append((char) ch);
}
assertEquals(sb.toString(), "一年之计在于春,一日之计在于晨");
}
LineNumberReader 支持行号的字符流
LineNumberReader 在 Reader 的基础上,新增了如下接口:
setLineNumber getLineNumber
{
BufferedWriter bw = new BufferedWriter(new FileWriter("/tmp/test.txt"));
bw.write("富贵不能淫/n贫贱不能移/n威武不能屈/n此之谓大丈夫/n");
bw.close();
}
{
LineNumberReader lr = new LineNumberReader(new BufferedReader(new FileReader("/tmp/test.txt")));
List<String> lines = new LinkedList<>();
for (String line = lr.readLine(); line != null; line = lr.readLine()) {
lines.add(lr.getLineNumber() + " " + line);
}
assertThat(lines, equalTo(List.of(
"1 富贵不能淫", "2 贫贱不能移", "3 威武不能屈", "4 此之谓大丈夫"
)));
}
可回退字符流内部维护了一个固定大小的缓冲区(可通过构造函数配置 buffer 的大小),允许将字符回退到缓冲区,如果超过了缓冲区大小,会抛出异常
PushbackReader 在 Reader 的基础上新增了如下接口:
unread unread(cbar[]) unread(char[], offset, length)
PushbackReader pr = new PushbackReader(new StringReader("蚍蜉撼大树,可笑不自量"), 10);
char[] buf = new char[5];
assertEquals(pr.read(buf), 5);
assertArrayEquals(buf, "蚍蜉撼大树".toCharArray());
pr.unread(buf);
assertEquals(pr.read(buf), 5);
assertArrayEquals(buf, "蚍蜉撼大树".toCharArray());
// 超过 buffer 的大小,抛出 IOException
assertThrows(IOException.class, () -> pr.unread("01234567890".toCharArray()));
PipedReader 和 PipedWriter 通过调用 connect 方法建立连接,往 PipedWriter 写入,能从 PipedReader 读取,这种管道模式是一对一的,对一个管道流建立两次连接会抛出异常
PipedWriter 在 Writer 的基础上提供如下接口:
connect : 与一个 PipedReader 建立连接,如果已经建立连接,将抛出异常 PipedReader 在 Reader 的基础上提供如下接口:
connect : 与一个 PipedWriter 建立连接,如果已经建立连接,将抛出异常 ExecutorService es = Executors.newCachedThreadPool();
PipedReader pr = new PipedReader();
PipedWriter pw = new PipedWriter();
pr.connect(pw);
es.execute(() -> {
try {
BufferedWriter bw = new BufferedWriter(pw);
bw.write("活着就是为了改变世界,难道还有其他原因吗");
bw.close();
} catch (Exception e) {
e.printStackTrace();
}
});
es.execute(() -> {
try {
BufferedReader br = new BufferedReader(pr);
assertEquals(br.readLine(), "活着就是为了改变世界,难道还有其他原因吗");
br.close();
} catch (Exception e) {
e.printStackTrace();
}
});
try {
es.shutdown();
while (!es.awaitTermination(1000, TimeUnit.MILLISECONDS)) {
// nothing to do
}
} catch (Exception e) {
e.printStackTrace();
}