JDK 1.7 java.io 源码学习之InputStream和OutputStream
来源:互联网 发布:python 查看硬盘分区表 编辑:程序博客网 时间:2024/04/30 21:04
InputStream和OutputStream是Java IO API 中所有字节输入/输出流的基类,是一个抽象类,实现了Cloaseable接口
InputStream 最核心的是三个read方法:
public abstract int read() throws IOException;
public int read(byte b[]) throws IOException;
public int read(byte b[], int off, int len) throws IOException;
第一个是抽象的read方法是后两个方法的基础,后两个方法均调用了该方法,该方法必须由子类实现。该方法表示一次读取一个字节的数据,如果已经到达流末尾则返回-1
第二个方法等效于第三个方法read(b, 0, b.length)
第三个方法表示一次可以最多读取len个数据字节缓存在byte数组b中,但读取的字节也可能小于该值,以整数的形式返回实际读取的字节数,如果已经到达流末尾则返回-1
public int read(byte b[], int off, int len) throws IOException;
/* * b[]是用于缓冲数据的字节数组 * len是最大读取的字节数,但读取的字节也可能小于该值 * off是b[]写入数据时的初始偏移量 */ public int read(byte b[], int off, int len) throws IOException { if (b == null) { // 缓存字节数组 未实例化 抛出NullPointException throw new NullPointerException(); } else if (off < 0 || len < 0 || len > b.length - off) { /* off偏移量小于0 * 或 最大读取字节数小于0 * 或 最大读取字节数超出了b[]数组长度减去偏移长度 * (即b[]缓冲数组无法保存本次读取的字节数据) * 抛出IndexOutOfBoundsException */ throw new IndexOutOfBoundsException(); } else if (len == 0) { //最大读取字节数是0 直接返回0 return 0; } // 读取第一个字节的数据 int c = read(); // 如果到达流末尾了则直接返回-1, 即该文件是个空文件 if (c == -1) { return -1; } //将读取的第一个字节数据存入缓冲数组b[off]中 b[off] = (byte)c; /* * 将读取的下一个字节数据存入缓冲数据b[off+1] * 循环读取下一次字节数据 * 任何情况下,b[0]-b[off] 和 b[off+len]-b[b.length-1] 都不会受影响 */ int i = 1; try { for (; i < len ; i++) { c = read(); // 若读取到流的末尾, 则结束读取 if (c == -1) { break; } //将读取的字节缓冲的缓冲字节数组内 b[off + i] = (byte)c; } } catch (IOException ee) { } // 最终读取的字节数 return i; }
现结合图示演示该方法的执行情况:
FileInputStream fis = new FileInputStream(new File("my.txt"));byte[] b = "123456789".getBytes();int off = 0;int len = 3;fis.read(b, off, len);fis.close();System.out.println(new String(b));
先假设my.txt中的内容如下:
这边UTF-8编码集,一个中文占3个字节,数字和英文以及空格占1个字节
my.txt内文件内容的字节数组示意如上图。
byte[] b 是准备用于缓冲读取的字节数据的字节数组,预先放置了一部分数据,方便于比对前后结果,示意如下图:
现假设off=0,len=3, 即最多读取3个字节的数据缓存在缓冲字节数组0-2下标处,实际结果示意如下图:
缓冲字节数组前三个字节已经被替换为汉字“流”
若off=0,len = 10,则将抛出IndexOutOfBoundsException
因为此时b.length = 9, b.length - off = 9,len > b.length - off ,即缓冲字节数组已经无法缓存一次性读取的字节内容了,放不下
若off=3,len = 3, 则实际结果示意如下图:
因为off = 3, 所以其实保存的数组下标需要进行偏移
同理若off=3,len = 8,则将抛出IndexOutOfBoundsException
因为此时b.length = 9, b.length - off = 6,len > b.length - off ,即缓冲字节数组已经无法缓存一次性读取的字节内容了,放不下
skip 方法
/** * 跳过多少字节的数据内容 */ public long skip(long n) throws IOException { // 重新保存该变量 long remaining = n; int nr; // 如果跳过的字节数小于等于0, 直接返回0 if (n <= 0) { return 0; } // 跳过的字节数不能超过2048, 取2048 和 传入的跳过字节数的较小值 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变量的值, 减去读取返回的字节数, 用于控制循环 remaining -= nr; } //返回实际跳过的字节数 return n - remaining; }
还是结合上述例子,只是中间执行一次skip方法:
FileInputStream fis = new FileInputStream(new File("my.txt"));byte[] b = "123456789".getBytes();int off = 0;int len = 3;fis.skip(3);fis.read(b, off, len);fis.close();System.out.println(new String(b));
实际结果如下图示意:
因为my.txt 的字节内容,被跳过了3个字节的数据,直接从其第4个字节的数据开始读取了
InputStream还有其他几个扩展方法,后续再具体详述
OutputSteam 对应的则有三个核心的write方法:
public abstract void write(int b) throws IOException;
public void write(byte b[]) throws IOException;
public void write(byte b[], int off, int len) throws IOException;
同理第一个是抽象的write方法是后两个方法的基础,后两个方法均调用了该方法,该方法必须由子类实现。该方法表示一次读取一个字节的数据,如果已经到达流末尾则返回-1
第二个方法等效于第三个方法write(b, 0, b.length)
第三个方法表示一次可以最多写出byte字节数组len的字节
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]); } }
首先还是一些异常情况的检查判断:
字节数组未实例化、off小于0、off大于字节数组长度、写入流的字节数小于0、off+len 大于字节数组长度、off+len 小于0 等情况
最后循环调用write(int b),一次一个字节的写入流中
还是结合图示说明:
OutputStream os = new FileOutputStream("my.txt");String content = "流.write 的常规";byte[] b = content.getBytes("UTF-8");os.write(b, 3, 13);os.flush();os.close();
实际写入流的是如下内容:
OutputStream 内还有close() 和 flush() 方法,这两个方法具体均需要子类去实现
这两个类暂时 看到这里了。
- JDK 1.7 java.io 源码学习之InputStream和OutputStream
- java IO之OutputStream和InputStream
- Java IO 系列源码分析——InputStream和OutputStream
- Java IO ---学习笔记(InputStream 和 OutputStream)
- Java--IO流之字节流介绍--InputStream和OutputStream
- Java.IO.InputStream-OutputStream
- Java IO - InputStream&OutputStream
- java io操作之InputStream,OutputStream
- java.io之InputStream与OutputStream
- Java IO 字节流 InputStream和OutputStream
- JAVA IO-2 InputStream和OutputStream
- Java知识(IO流、.InputStream和OutputStream)
- Java IO流-InputStream和OutputStream
- 2 Java IO:InputStream 和 OutputStream
- java学习之字节流--InputStream和OutputStream
- JAVA IO源码学习系列之InputStream
- Java IO 之 OutputStream源码
- 学习笔记之java.io包中的字节流(上)—— 基本的InputStream和OutputStream
- 机器学习资料与攻略超强整理吐血推荐(二)
- 理解AccessibilityService
- JNDI(Tomcat中的资源池)配置简介
- linux下 tomact的8080端口别占用了,解决办法
- 使用Handler控制进度条,完成开始、暂停、继续、停止操作
- JDK 1.7 java.io 源码学习之InputStream和OutputStream
- Codeblocks: 在工作空间中添加多个工程
- 决策树和基于决策树的集成方法(DT,RF,GBDT,XGB)复习总结
- PLSQL Bulk Bind (FETCH BULK COLLECT INTO)
- 一个管道转角Mesh的实现方法
- Java如何读取和操作上G文本
- Android开发环境搭建
- 需要两个ssh key
- linux shell 正则表达式(BREs,EREs,PREs)差异比较