Java I/O系列(一)InputStream与OutputStream源码分析及理解

1. InputStream

定义


字节输入流,是一个抽象类,核心是通过read()方法,从数据源中读取一个个字节出来,另有skip,mark功能

Java I/O系列(一)InputStream与OutputStream源码分析及理解

核心源码理解


源码:

public abstract int read() throws IOException;

理解:

1. 抽象方法,必须由子类实现;从什么地方读?数据源来自哪里?这个是由子类提供的,如FileInputStream是从文件中读,ByteArrayInputStream是从byte数组中读...

2. 每次读取都只会读取一个字节,一个byte出来,是有顺序的,读完这个字节,会自动跳到下一个字节等待读取

3. 注意返回值的定义是int,不是byte:如果有byte可读,就返回这个byte对应的无符号类型的值(0 - 255),返回值可以理解成某个“字符”的ASCII码值(如读取到A了,那么就会返回65);如果没有byte可读就直接返回-1

源码:

 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;
}

理解:

1. 这个方法比较好理解,循环调用read()方法,将读取到的int转换成byte,然后再放到参数b的特定位置(从off开始放,放len个,当然可能放不满len个,是等待读取的字节数而定);注意子类可能会重写这个方法,会有另外的实现

2. 返回值是实际读出来的字节数,如果没有则返回-1

2. OutPutStream

定义


字节输出流,也是一个抽象类,核心是通过write()方法,一个一个字节的写入到目的数据源中(由子类决定)

Java I/O系列(一)InputStream与OutputStream源码分析及理解

核心源码理解


源码:

public abstract void write(int b) throws IOException;

理解:

1. 抽象方法,必须由子类实现;写入到哪儿呢,由子类决定

2. 参数b是作为要写入的数据,是int类型不是byte类型;因为int是占4个字节共32位,这里规定的是取低8位,忽略高24位,所以最后写入的是一个字节;参数可以理解成某个ASCII码值的十进制,写入的就是对应的“字符”(如b=65时,写入的就是A)

源码:

 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]);
}
}

理解:

1. 循环调用write()方法,将b[off] 到 b[off + len - 1] 的值写入到目的数据源

3. 总结:


1. 细心的可能会发现,read()方法返回值的范围是0 - 255,而byte本身范围是-128 - 127, 这样的转换其实是有符号byte类型到无符号类型的转换,做法是 int a = b & oxff, 其中b是有符号类型的byte   具体参考:https://www.jianshu.com/p/db85f033e75c

2. skip比较简单,其实现是将待跳过的部分读取出来而不使用;mark与reset结合使用都没有给出默认实现,由子类实现

3. 注意write(int b) 方法,是取b的低8位,忽略b的高24位

4. 问题:


1. 欢迎大家提出问题,共同交流学习!

5. 示例:


6. 参考:


1. https://www.jianshu.com/p/db85f033e75c

上一篇:输入和输出(read,recv,recvmsg...和write,writev,writemsg)


下一篇:【5.1送礼】国内第一部Matlab和C#.Net混合编程视频教程【免费】