Java SE《基础篇》——(十)IO
流概述
概念
流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象。
即数据在两设备间的传输称为流,流的本质是数据传输,根据数据传输特性将流抽象为各种类,方便更直观的进行数据操作。
分类
- 按处理数据类型的不同,分为字节流和字符流
- 按数据流向的不同,分为输入流和输出流。(入和出是相对于内存来讲的)
- 按功能不同,分为节点流和处理流
- 节点流:直接操作数据源
- 处理流:对其他流进行处理
抽象类定义
InputStream
InputStream的继承关系:蓝色为节点流,黑色为处理流(小红旗重点)
【常用方法】
方法 描述 void close() 关闭此输入流并释放与该流关联的所有系统资源 abstract int read() 从输入流读取下一个数据字节 int read(byte[] b) 从输入流中读取一定数量的字节并将其存储在缓冲区数组b中 int read(byte[] b, int off, int len) 将输入流中最多len个数据字节读入字节数组
OutputStream
OutputStream的继承关系:蓝色为节点流,黑色为处理流(小红旗重点)
【常用方法】
方法 描述 void close() 关闭此输出流并释放与此流有关的所有系统资源 void flush() 刷新此输出流并强制写出所有缓冲的输出字节 void write(byte[] b) 将 b.length个字节从指定的字节数组写入此输出流 void write(byte[] b, int off, int len) 将指定字节数组中从偏移量 off 开始的 len 个字节写入此输出流 abstract void write(int b) 将指定的字节写入此输出流
Reader
Reader的继承关系:蓝色为节点流,黑色为处理流(小红旗重点)
【常用方法】
方法 描述 abstract void close() 关闭该流 int read() 读取单个字符 int read(char[] cbuf) 将字符读入数组 abstract int read(char[] cbuf, int off, int len) 将字符读入数组的某一部分
Writer
Writer的继承关系:蓝色为节点流,黑色为处理流(小红旗重点 )
【常用方法】
方法 描述 void write(int c) 写入单个字符 void write(char[] cbuf) 写入字符数组 abstract void write(char[] cbuf, int off, int len) 写入字符数组的某一部分 void write(String str) 写入字符串 void write(String str, int off, int len) 写入字符串的某一部分 Writer append(char c) 将指定字符添加到此writer abstract void flush() 刷新该流的缓冲 abstract void close() 关闭此流,但要先刷新它
示例
读取一个文件,把文件的字符一行行打印到控制台上。
File文件操作
常用方法
还有一个重要方法:
createNewFile() : 真正生成磁盘中的文件
创建文件、删除文件
public class TestFileOperator {
public static void main(String[] args) throws Exception {
File txtFile = new File("auto_create.txt");
if (!txtFile.exists()) {
txtFile.createNewFile();
} else {
System.out.println("file existed");
System.out.println("txtFile.delete()=" + txtFile.delete());
}
}
}
【示例】 动手实现获取给定一个File对象,其下的所有文件和目录的绝对路径
文件流
分类 | 字节流 | 字符流 |
---|---|---|
文件输入流 | FileInputStream | FileReader |
文件输出流 | FileOutputStream | FileWriter |
【示例】
演示四个文件流的使用(文件读取和文件写入)
缓冲流
分类 | 字节流 | 字符流 |
---|---|---|
文件输入流 | BufferedInputStream | BufferedReader |
文件输出流 | BufferedOutputStream | BufferedWriter |
【特点】
- 主要是为了提高效率而存在的,减少物理读取次数
- 提供readLine()、newLine()这样的便捷的方法(针对缓冲字符流)
- 在读取和写入时,会有缓存部分,调用flush为刷新缓存,将内存数据写入到磁盘
【示例】
演示四个缓冲流的使用(文件读取缓冲和文件写入缓冲)
转换流
输入流 | 输出流 |
---|---|
InputStreamReader | OutputStreamWriter |
【特点】
- 转换流是指将字节流向字符流的转换,主要有InputStreamReader和OutputStreamWriter
- InputStreamReader主要是将字节流输入流转换成字符输入流
- OutputStreamWriter主要是将字节流输出流转换成字符输出流
InputStreamReader
分类 | 方法 | 描述 |
---|---|---|
构造方法 | InputStreamReader(InputStream in) InputStreamReader(InputStream in,Charset cs) InputStreamReader(InputStream in,CharsetDecoder dec) InputStreamReader(InputStream in,String charsetName) |
创建一个使用默认字符集的该对象 创建使用给定字符集的该对象 创建使用给定字符集解码器的该对象 创建使用指定字符集该对象 |
常用方法 | void close() String getEncoding() int read() int read(char[] cbuf, int offset, int length) boolean ready() |
关闭该流并释放与之关联的所有资源 返回此流使用的字符编码的名称 读取单个字符 将字符读入数组中的某一部分 判断此流是否已经准备好用于读取 |
OutputStreamWriter
参考InputStreamReader
打印流
【特点】
- 打印流是输出最方便的类
- 包含字节打印流PrintStream,字符打印流PrintWriter
- PrintStream是OutputStream的子类,把一个输出流的实例传递到打印流之后,可以更加方便地输出内容,相当于把输出流重新包装一下
- PrintStream类的print()方法被重载很多次print(int i)、print(boolean b)、print(char c)
【示例】
使用StringReader读取字符串,然后使用打印流打印到控制台。
【标准输入/输出】
- Java的标准输入/输出分别通过System.in和System.out来代表,在默认的情况下分别代表键盘和显示器,当程序通过System.in来获得输入时,实际上是通过键盘获得输入。当程序通过System.out执行输出时,程序总是输出到屏幕。
- 在System类中提供了三个重定向标准输入/输出的方法
- static void setErr(PrintStream err) 重定向“标准”错误输出流
- static void setIn(InputStream in) 重定向“标准”输入流
- static void setOut(PrintStream out)重定向“标准”输出流
【示例】
使用重定向实现文件复制
对象流
输入流 | 输出流 |
---|---|
ObejctInputStream | ObejctOutputStream |
【概念】
1. 对象流,即为以Java对象为传输主体的IO过程。Java对象必须要被序列化后方可进行传输。
2. 所谓的对象的序列化就是将对象转换成二进制数据流的一种实现手段,通过将对象序列化,可以方便的实现对象的传输及保存。
3. 要想实现对象的序列化需要实现Serializable接口,但是Serializable接口中没有定义任何的方法,仅仅被用作一种标记,以被编译器作特殊处理。
4. 在Java中提供了ObejctInputStream 和ObjectOutputStream这两个类用于序列化对象的操作。
5. 对象的序列化的实现方便了对象间的克隆,使得复制品实体的变化不会引起原对象实体的变化。
【示例】
把学生对象序列化输出到文件,然后再从文件还原成对象。
【transient和serialVersionUID】
这两个知识点,大家下面自行练习。
- transient
- 当对象被序列化时(写入字节序列到目标文件)时,transient阻止实例中那些用此关键字声明的变量持久化;当对象被反序列化时(从源文件读取字节序列进行重构),这样的实例变量值不会被持久化和恢复。若要序列化的对象中含有流、线程引用,则请将其修饰加上关键字transient。
- serialVersionUID
- 其目的是序列化对象版本控制,有关各版本反序列化时是否兼容。如果在新版本中这个值修改了,新版本就不兼容旧版本,反序列化时会抛出InvalidClassException异常。如果修改较小,比如仅仅是增加了一个属性,我们希望向下兼容,老版本的数据都能保留,那就不用修改;如果我们删除了一个属性,或者更改了类的继承关系,必然不兼容旧数据,这时就应该手动更新版本号,即SerialVersionUid。
下一篇: Android -Webview内存泄漏