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

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

努力工作,用心生活

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

时间: 2024-10-18 22:03:38

java(jdk1.7) IO系列01之InputStream和OutputStream解析的相关文章

java io系列01之 &quot;目录&quot;

javaIO系列转载出处:http://www.cnblogs.com/skywang12345/p/io_01.html 该分类所有博文,均转载同一作者,后边不再累赘标名. java io 系列目录如下: 01. java io系列01之  "目录" 02. java io系列02之 ByteArrayInputStream的简介,源码分析和示例(包括InputStream) 03. java io系列03之 ByteArrayOutputStream的简介,源码分析和示例(包括Ou

java IO(二):字节流(InputStream和OutputStream)

*/ .hljs { display: block; overflow-x: auto; padding: 0.5em; color: #333; background: #f8f8f8; } .hljs-comment, .hljs-template_comment, .diff .hljs-header, .hljs-javadoc { color: #998; font-style: italic; } .hljs-keyword, .css .rule .hljs-keyword, .h

java 20 - 4 IO流概述和一个简单例子解析

IO流的分类:  流向: 输入流 读取数据  输出流 写出数据 数据类型:  字节流  字节输入流 读取数据 InputStream  字节输出流 写出数据 OutputStream  字符流  字符输入流 读取数据 Reader  字符输出流 写出数据 Writer 注意:一般我们在探讨IO流的时候,如果没有明确说明按哪种分类来说,默认情况下是按照数据类型来分的. ------------------------------------割割割--------------------------

Java之IO(一)InputStream和OutputStream

转载请注明源出处:http://www.cnblogs.com/lighten/p/6964702.html 1.前言 计算机的IO操作一直都是比较重要的一环,IO顾名思义,就是输入输出流.不管是磁盘IO还是网络IO,数据流转就离不开IO,理解Java的IO操作类很重要,本文介绍IO的抽象父类InputStream和OutputStream,这是Java的IO操作基础,理解完抽象类,对于其它的IO流也有很大的帮助. 流都实现了Closeable接口,也就是都需要关闭.输出流额外实现了一个Flus

Java 之 I/O 系列 02 ——序列化

Java 之 I/O 系列 目录 Java 之 I/O 系列 01 ——基础 Java 之 I/O 系列 02 ——序列化 一 序列化概述 序列化,简单来讲,就是以“流”的方式来保存对象,至于保存的目标地址,可以是文件,可以是数据库,也可以是网络,即通过网络将对象从一个节点传递到另一个节点. 在Java的I/O结构中,有ObjectOutputStream和ObjectInputStream,它们可以实现将对象输出为二进制流,并从二进制流中获取对象,那为什么还需要序列化呢?这需要从Java变量的

Java 之 I/O 系列 02 ——序列化(二)

Java 之 I/O 系列 目录 Java 之 I/O 系列 01 ——基础 Java 之 I/O 系列 02 ——序列化(一) Java 之 I/O 系列 02 ——序列化(二) 继续上篇的第二个问题 如果一个类实现了Serializable接口,但是它的父类没有实现 ,这个类可不可以序列化? Object是每个类的超类,但是它没有实现 Serializable接口,但是我们照样在序列化对象,所以说明一个类要序列化,它的父类不一定要实现Serializable接口.但是在父类中定义 的状态能被

ojdbc在linux环境下 java.sql.SQLRecoverableException: IO Error: Connection reset 的问题

开门见山,最快捷的解决方案:java -Djava.security.egd=file:///dev/urandom  -jar  xxxxxxx.jar 描述下问题:写了个jar工具,用到了连接池,ojdbc.windows环境一起正常.linux环境下启动关闭两三次后就出现 java.sql.SQLRecoverableException: IO 错误: Connection reset 查看配置文件和解析问题, 无果. 更换hikari到druid,无果. 使用最新ojdbc包,无果. 无

java io系列02之 ByteArrayInputStream的简介,源码分析和示例(包括InputStream)

我们以ByteArrayInputStream,拉开对字节类型的“输入流”的学习序幕.本章,我们会先对ByteArrayInputStream进行介绍,然后深入了解一下它的源码,最后通过示例来掌握它的用法. 转载请注明出处:http://www.cnblogs.com/skywang12345/p/io_02.html ByteArrayInputStream 介绍 ByteArrayInputStream 是字节数组输入流.它继承于InputStream.它包含一个内部缓冲区,该缓冲区包含从流

java io系列04之 管道(PipedOutputStream和PipedInputStream)的简介,源码分析和示例

本章,我们对java 管道进行学习. 转载请注明出处:http://www.cnblogs.com/skywang12345/p/io_04.html java 管道介绍 在java中,PipedOutputStream和PipedInputStream分别是管道输出流和管道输入流.它们的作用是让多线程可以通过管道进行线程间的通讯.在使用管道通信时,必须将PipedOutputStream和PipedInputStream配套使用.使 用管道通信时,大致的流程是:我们在线程A中向PipedOut