首页 > 代码库 > java(jdk1.7) IO系列01之InputStream和OutputStream解析

java(jdk1.7) IO系列01之InputStream和OutputStream解析

1.InputStream和OutputStream简介

在java中InputStream和OutputStream分别代表字节输入流和字节输出流,表示以字节的方式来实现进程或者程序的通信,InputStream是输入流,表示以字节的方式从文件(FileInputStream)或者字节数组(ByteArrayInputStream)等读取数据,与之相对应的OutputStream是输出流,表示以字节的方式向文件(FileOutputStream)或者字节数组(ByteArrayOutputStream)等写入数据,InputStream和OutputStream分别是所有的字节流的超类,定义了字节输入流和字节输出流的抽象方法和公用实现,这里使用设计模式中的模版模式,超类定义一些公用的实现和相关的方法的约束,子类实现。下面让我们来看一些InputStream和OutputStream的源码

2.InputStream源码解析

 1 package java.io;
 2 public abstract class InputStream implements Closeable {
 3 
 4     //定义可以跳过的最大字节数
 5     private static final int MAX_SKIP_BUFFER_SIZE = 2048;
 6 
 7    //抽象读取方法,定义读取一个字节的方法约束,让子类去实现,
 8     public abstract int read() throws IOException;
 9 
10   //把读取的字节放到byte数组中,返回的是读取字节的数量
11     public int read(byte b[]) throws IOException {
12         return read(b, 0, b.length);
13     }
14   //具体的读取字节到字节数组的实现,并提供读取到字节数组b的起始位置off和读入的长度len
15     public int read(byte b[], int off, int len) throws IOException {
16         if (b == null) {
17             throw new NullPointerException();
18         } else if (off < 0 || len < 0 || len > b.length - off) {
19             throw new IndexOutOfBoundsException();
20         } else if (len == 0) {
21             return 0;
22         }
23         //先读取一个字节,如果返回-1,说明当前流中没有数据,直接返回-1
24         int c = read();
25         if (c == -1) {
26             return -1;
27         }
28      //如果有数据,则把数据存到b中
29         b[off] = (byte)c;
30 
31         int i = 1;
32         try {
33             //通过循环读取,然后把读取的内容存到传入的buffer中
34             for (; i < len ; i++) {
35                 c = read();
36           //如果返回-1,则表示当前读取到文件的结尾
37                 if (c == -1) {
38                     break;
39                 }
40                 b[off + i] = (byte)c;
41             }
42         } catch (IOException ee) {
43         }
44         return i;//返回读取的字节的数量
45     }
46 
47     //返回真实跳过的字节的数量
48     public long skip(long n) throws IOException {
49         
50         long remaining = n;
51         int nr;
52         //如果当前要求跳过0个,则直接返回0
53         if (n <= 0) {
54             return 0;
55         }
56         //字符缓冲区的大小不能大于2048.跳过的数量n可能大于2048.
57     //这里有个原因,为什么不直接声明一个和跳过字节n一样大小的数组。因为内存是个很昂贵的资源,如果一个文件很大的话,一次在内存中声明一个很大的内存,
58     //一方面会占用很大的内存,另一方面也影响垃圾回收
59 
60 
61         int size = (int)Math.min(MAX_SKIP_BUFFER_SIZE, remaining);
62         byte[] skipBuffer = new byte[size];//定义一个缓冲记录跳过的字节的数量
63         while (remaining > 0) {
64             //如果跳过的数量大于2048,则通过缓冲区多次执行read方法计算跳过的数量
65             nr = read(skipBuffer, 0, (int)Math.min(size, remaining));
66             if (nr < 0) {
67                 break;
68             }
69             remaining -= nr;
70         }
71      //返回实际跳过的字节的数量
72         return n - remaining;
73     }
74     //返回有多少数据能够读取
75     public int available() throws IOException {
76         return 0;
77     }
78 
79     //关闭流,留给子类去实现
80     public void close() throws IOException {}
81 
82    //标记一个位置,然后执行reset方法的时候可以重新回到标记的位置
83     public synchronized void mark(int readlimit) {}
84 
85    //重新从标记的位置读取
86     public synchronized void reset() throws IOException {
87         throw new IOException("mark/reset not supported");
88     }
89 
90     //表明是否支持标记功能
91     public boolean markSupported() {
92         return false;
93     }
94 
95 }

 

 3.OutputSteam源码解析

 1 public abstract class OutputStream implements Closeable, Flushable {
 2     //写入一个字节b到输入流
 3     public abstract void write(int b) throws IOException;
 4 
 5    //把字节数组b中的字节写入到输入流中
 6     public void write(byte b[]) throws IOException {
 7         write(b, 0, b.length);
 8     }
 9 
10    //把字节数组b中的字节写入到输入流中,并提供控制参数,从字节数组的那个位置开始读取,以及读取多长的长度
11     public void write(byte b[], int off, int len) throws IOException {
12         if (b == null) {
13             throw new NullPointerException();
14         } else if ((off < 0) || (off > b.length) || (len < 0) ||
15                    ((off + len) > b.length) || ((off + len) < 0)) {
16             throw new IndexOutOfBoundsException();
17         } else if (len == 0) {
18             return;
19         }
20         for (int i = 0 ; i < len ; i++) {
21             write(b[off + i]);
22         }
23     }
24 
25   //刷新输出流,强制把字符缓冲中的字节从内存中写入到输出流中,如果输出流是内存比如ByteArrayOutputStream等,则该实现为空
26 
27     public void flush() throws IOException {
28     }
29 
30     //关闭输出流,并释放资源,如果子类不需要,则该实现为空
31     public void close() throws IOException {
32     }
33 
34 }

 

 4.结语

虽然InputStream和OutputStream的两个抽象类的实现比较简单,代码量比较少,但是我们还是可以从中学到一些东西,比如模版设计模式的使用方法,代码中对方法参数的校验逻辑等。多多体会别人写的代码,总会学到一些东西,或许现在看不出来有什么用,但是对你的影响会慢慢看出来的。

 

===============================================================

努力工作,用心生活

===============================================================

 

java(jdk1.7) IO系列01之InputStream和OutputStream解析