Java I/O 05 - InputStream & OutputStream

  关于 java.io.InputStream java.io.OutputStream 的部分笔记,这两个类是字节流读写的公共父类,继承这两个类的子类均实现了读、写操作。本文演示代码段的执行环境基于JDK版本1.7

概述

  这两个类的设计都比较简单,其作为抽象类的存在给继承这两个类的子类留下了各自的实现read()和write()方法的空间,使得各个子类可以根据具体的设计需要分别有针对性的设计和实现字节流的读写。

继承关系

1
2
3
4
5
6
7
// InputStream
--java.lang.Object
--java.io.InputStream

// OutputStream
--java.lang.Object
--java.io.OutputStream

实现接口

类名 实现接口
InputStream Closeable, AutoCloseable
OutputStream Closeable, Flushable, AutoCloseable

部分方法

InputStream:public long skip(long n)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public long skip(long n) throws IOException {
long remaining = n;
int nr;

if (n <= 0) {
return 0;
}

int size = (int)Math.min(MAX_SKIP_BUFFER_SIZE, remaining);
byte[] skipBuffer = new byte[size];
while (remaining > 0) {
nr = read(skipBuffer, 0, (int)Math.min(size, remaining));
if (nr < 0) {
break;
}
remaining -= nr;
}

return n - remaining;
}

  该方法会跳过读入内容的指定长度,读取位置会从当前位置向后偏移最多n个长度。为什么说是最多n个呢?我们浏览下第11 ~ 17行代码,代码的期望执行结果是remaining为0,跳出循环,最后返回入参n。这样实际跳过的长度和入参相同。但是在实际执行过程中,有可能输入流读取会直接到流结束的位置,这样循环就会提前跳出,最后remaining的值大于0,那么最终返回的长度会小于入参n。在第9行代码,通过MAX_SKIP_BUFFER_SIZE (2048)和入参取较小值,从而控制单次读取的最大长度。

InputStream:public int read(byte b[], int off, int len)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public int read(byte b[], int off, int len) throws IOException {
if (b == null) {
throw new NullPointerException();
} else if (off < 0 || len < 0 || len > b.length - off) {
throw new IndexOutOfBoundsException();
} else if (len == 0) {
return 0;
}

int c = read();
if (c == -1) {
return -1;
}
b[off] = (byte)c;

int i = 1;
try {
for (; i < len ; i++) {
c = read();
if (c == -1) {
break;
}
b[off + i] = (byte)c;
}
} catch (IOException ee) {
}
return i;
}

  读取多个字节的内容保存到入参数组b中并返回读取的字节数。在做完参数的有效性校验后,首先从底层输入流中尝试读出一个字节的内容,如果说读取时出现了非读到文件结束以外的其他异常的话,那么读取就会终止。如果可以正常读取,那么就循环调用read()方法,每次读取一个字节并将读取的内容保存到入参数组b中,直到读取到指定长度的内容,或者文件已经被读完。最后返回实际读取的字节长度。

OutputStream:public void write(byte b[], int off, int len)

1
2
3
4
5
6
7
8
9
10
11
12
13
public void write(byte b[], int off, int len) throws IOException {
if (b == null) {
throw new NullPointerException();
} else if ((off < 0) || (off > b.length) || (len < 0) ||
((off + len) > b.length) || ((off + len) < 0)) {
throw new IndexOutOfBoundsException();
} else if (len == 0) {
return;
}
for (int i = 0 ; i < len ; i++) {
write(b[off + i]);
}
}

  写入多个字节到入参数组b中。在内部其实是循环调用write(int b)来实现多字节写入的。write(int b)这个方法由继承的子类分别实现。

涉及基础知识点

  1. FilterOutputStream的close方法执行逻辑:

    1
    2
    3
    4
    5
    6
    7
    public void close() throws IOException {
    try {
    flush();
    } catch (IOException ignored) {
    }
    out.close();
    }

    首先将数据全部推送到输出流中,之后再执行底层输出流的close方法。

参考文献

NIL




------------- End of this article, thanks! -------------


  版权声明:本文由Nathan R. Lee创作和发表,采用署名(BY)-非商业性使用(NC)-相同方式共享(SA)国际许可协议进行许可,转载请注明作者及出处。
  本文作者为 Nathan R. Lee
  本文标题为 Java I/O 05 - InputStream & OutputStream
  本文链接为 https://marcuseddie.github.io/2018/java-InputStream-OutputStream.html