Java 输入输出
输出允许程序读取外部数据,输入允许程序记录运行状态、输出数据。
一、File
1. File
File 是文件/目录的抽象表示,通过文件/目录的路径字符串创建 File 实例。
File 不能访问文件内容,但可以新建、删除文件/目录。
2. 方法
(1) 创建 File 对象
方法 | 说明 |
---|---|
new File(String pathname) | 根据 pathname 字符串创建 File 对象 |
new File(String parent, String child) | 根据 parent 和 child 字符串创建 File 对象 |
new File(File parent, String child); | 根据父对象和 child 字符串创建 File 对象 |
1
2
3
4
5
6
7
8
9
10
public class Test {
public static void main(String[] args) {
File file1 = new File("D:\\Test");
File file2 = new File("D:\\Test","hello");
File file3 = new File(file1,"hello");
System.out.println(file1);
System.out.println(file2);
System.out.println(file3);
}
}
(2) 创建
方法 | 说明 |
---|---|
creatNewFile() | 创建文件 |
mkdir() | 创建目录 |
mkdirs() | 创建目录,包括不存在的父目录 |
(3) 判断
方法 | 说明 |
---|---|
exists() | 判断文件/目录是否存在 |
isFile() | 判断是否为文件 |
isDirectory() | 判断是否为目录 |
(4) 获取
方法 | 说明 |
---|---|
getName() | 获取文件名/目录名 |
get[Absolute]Path() | 获取[绝对]路径 |
list() | 获取由目录中的文件名/目录名组成的数组 |
listFiles() | 获取由目录中的文件/目录的 File 对象组成的数组 |
(5) 删除
方法 | 说明 |
---|---|
delete() | 删除文件/目录 |
需要注意的是:仅在目录被清空时,目录才可以被删除
二、IO 流
1. 什么是 IO 流?
IO 流,Input/Output 流,即输入/输出流。
在 Java 中把不同的输入/输出源抽象表述为“流“,通过”流“允许程序以相同的方式访问不同的输入/输出源。
2. IO 流的分类
(1) 输入流和输出流
根据数据的流向,可以将 IO 流分为:
- 输入流
- 输出流
其中,输入/输出是以内存的角度进行划分的,向内存中输入数据为输入流,从内存向外输出数据为输出流。
(2) 字节流和字符流
根据操作的数据单元不同,可以将 IO 流分为:
- 字节流:操作的数据单元是字节
- 字符流:操作的数据单元是字符
字节流可以处理一切文件
字符流只能处理文本
(3) 节点流和处理流
- 节点流:向一个特定的 I/O 设备读/写数据
- 处理流:对已存在的流进行封装,从而实现同一份代码读/写不同节点的数据
(4) 缓冲流
由于程序和内存之间的交互很快,内存和磁盘之间的交互很慢,访问外部数据时,最多的时间是在等外部设备响应,而不是数据处理。为提升程序效率,引入了缓冲流。
缓冲流的做法是在内存中设置一个缓冲区,待缓冲区存储够足够的数据后再进行读取和写入,通过提高每次交互的数据量,减少了交互次数。
3. flush()
在处理缓冲流时,应该确保执行了 flush()
,将缓冲区中的数据输出到物流节点上,防止数据丢失。
4. close()
在流使用结束后,应该关闭流。关闭流可以保证与该流关联的所有系统资源被回收,并且还可以执行缓冲流的 flush()
。
通过流的 close()
方法可以对流进行关闭,为确保始终执行 close()
方法,可以:
(1) finally
在 finally 中调用 close()
方法,从而确保 close()
方法一定被执行。
1 |
|
(2) 自动收尾
Java7 之后,支持“自动收尾”写法,并且所有的 IO 类均实现了 AutoCloseable 接口。
可以在 try 之后紧跟 ( )
,在其中放置 IO 类,IO 类将会在 try-catch 语句执行后被自动关闭。
1 |
|
三、输入流
1. 抽象父类
InputStream 和 Reader 是所有输入流的抽象父类。
(1) InputStream
字节输入流
方法 | 说明 |
---|---|
read() | 从流中读取单个字节 |
read(byte[] b) | 从流中读取最多 b.length 个字节,放入字节数组 b |
read(byte[] b, int off, int len) | 从流中读取最多 len 个字节,从字节数组的 off 索引处开始,依次放入 |
方法 | 说明 |
---|---|
close() | 关闭流并释放与此流有关的所有系统资源 |
(2) Reader
字符输入流
方法 | 说明 |
---|---|
read() | 从流中读取单个字节 |
read(char[] c) | 从流中读取最多 c.length 个字符,放入字符数组 c |
read(char[] c, int off, int len) | 从流中读取最多 len 个字符,从字符数组的 off 索引处开始,依次放入 |
方法 | 说明 |
---|---|
close() | 关闭流并释放与此流有关的所有系统资源 |
2. 节点流实现类
常用的输入流实现类有 FileInputStream 和 FileReader 。
1 |
|
四、输出流
1. 抽象父类
OutputStream 和 Writer 是所有输出流的抽象父类。
(1) OutputStream
字节输出流
方法 | 说明 |
---|---|
write(int/char c) | 将字节/字符输出到流中,其中字节/字符可以以数字/字符表示 |
write(byte[] b) | 将字节数组 b 中的数据输出到流中 |
write(byte[] b, int off, int len) | 将字节数组 b 中从 off 索引处开始,长度为 len 的数据输出到流中 |
方法 | 说明 |
---|---|
close() | 关闭流并释放与此流有关的所有系统资源 |
(2) Writer
字符输出流
方法 | 说明 |
---|---|
write(int/char c) | 将字节/字符输出到流中,其中字节/字符可以以数字/字符表示 |
write(char[] c) | 将字符数组 c 中的数据输出到流中 |
write(char[] c, int off, int len) | 将字符数组 c 中从 off 索引处开始,长度为 len 的数据输出到流中 |
write(String str) | 将字符串 str 中的数据输出到流中 |
write(String str, int off, int len) | 将字符串 str 中从 off 位置开始,长度为 len 的数据输出到流中 |
方法 | 说明 |
---|---|
flush() | 刷新流并强制输出所有缓冲的输出字符 |
close() | 刷新流,关闭流并释放与此流有关的所有系统资源 |
2. 节点流实现类
常用的输入流实现类有 FileOutputStream 和 FileWriter 。
1 |
|
五、对象序列化
1. 什么是对象序列化?
对象序列化的目标是将对象转换为可保存、可传输的二进制流,允许将对象传输至其它节点,或持久地保存在磁盘上。
对象序列化使得对象可以脱离程序的运行而独立存在。
2. 对象序列化的前提
如果需要让某个对象支持序列化,则必须让它的类实现以下接口之一:
Serializable
仅仅是一个标记接口,实现该接口无需实现任何方法
Externalizable
3. 序列化
创建节点输出流
通过节点输出流创建 ObjectOutputStream 流
1
ObjectOutputStream objectOutputStream = new ObjectOutputStream(节点流)
调用 ObjectOutputStream 流中的
writeObject()
输出对象1
objectOutputStream.writeObject(obj)
4. 反序列化
创建节点输入流
通过节点输入流创建 ObjectInputStream 流
1
ObjectInputStream objectInputStream = new ObjectInputStream(节点流)
调用 ObjectInputStream 流中的
readObject()
输出对象1
Object obj = objectInputStream.readObject()
5. SerializableID
在实际开发中,代码不断迭代,类可能新增、删除属性,如果某个对象在早些时候序列化,在类已经修改后进行反序列化,可能会因不兼容出现异常。
为避免这一问题,可以通过 SerializableID 对类的版本做唯一标识。
具体来说,有两种做法:
显式声明:在类中声明 SerializableID,并在类更新时手动修改
1
2
3public class MyClass implements Serializable {
private static final long serialVersionUID = 123456789L;
}隐式生成:Java 会根据类的包、字段、方法等信息生成一个隐式的 SerializableID
参考
疯狂 Java 讲义