如需转载,请根据 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 许可,附上本文作者及链接。
本文作者: 执笔成念
作者昵称: zbcn
本文链接: https://1363653611.github.io/zbcn.github.io/2020/10/03/IO_02%E5%B8%B8%E7%94%A8%E7%9A%84%E6%B5%81/
文件流
- 输入:
FileInputStream/FileReader
- 输出:
FileOutputStream/FileWriter
InputStream和Reader都是抽象类,本身不能创建实例,但它们分别有一个用于读取文件的输入流:FileInputStream和FileReader.它们都是节点流(会直接和指定文件关联
使用FileInputStream和FileOutputStream读取/写入文件
1 | private static void streamTest() { |
2 | |
3 | InputStream fis = null; |
4 | OutputStream fos = null; |
5 | try { |
6 | fis = new FileInputStream("D:/javaTest/test1.txt"); |
7 | //该方法如果文件不存在会自动创建文件 |
8 | fos = new FileOutputStream("D:/javaTest/test2.txt"); |
9 | byte[] bytes = new byte[1024]; |
10 | int len = 0; |
11 | while ((len = fis.read(bytes)) != -1){ |
12 | System.out.println(new String(bytes,0,len)); |
13 | fos.write(bytes,0,len); |
14 | } |
15 | }catch (IOException e) { |
16 | e.printStackTrace(); |
17 | }finally { |
18 | try { |
19 | fis.close(); |
20 | } catch (IOException e) { |
21 | e.printStackTrace(); |
22 | } |
23 | //关闭前回flush |
24 | try { |
25 | fos.close(); |
26 | } catch (IOException e) { |
27 | e.printStackTrace(); |
28 | } |
29 | } |
30 | } |
FileReader 和FilerWriter 读取数据输出到文件
1 | /** |
2 | * 字符集操作 |
3 | */ |
4 | private static void readAndWrite() { |
5 | Reader reader = null; |
6 | Writer wt = null; |
7 | try { |
8 | reader = new FileReader("D:/javaTest/test1.txt"); |
9 | wt = new FileWriter("D:/javaTest/test2.txt"); |
10 | char[] ch = new char[1024]; |
11 | int len = 0; |
12 | while ((len = reader.read(ch)) != -1){ |
13 | System.out.println( new String(ch,0,len)); |
14 | wt.write(ch,0,len); |
15 | } |
16 | |
17 | } catch (FileNotFoundException e) { |
18 | e.printStackTrace(); |
19 | } catch (IOException e) { |
20 | e.printStackTrace(); |
21 | }finally { |
22 | try { |
23 | reader.close(); |
24 | wt.close(); |
25 | } catch (IOException e) { |
26 | e.printStackTrace(); |
27 | } |
28 | } |
29 | } |
缓冲流
- 输入:
BufferedInputStream/BufferedReader
- 输出:
BufferedOutputStream/BufferedWriter
缓冲流是处理流的一种, 它依赖于原始的输入输出流, 它令输入输出流具有1个缓冲区, 显著减少与外部设备的IO次数, 而且提供一些额外的方法.
实际上很多常用的程序都有用到缓冲流的技术, 例如迅雷下载, 有缓冲区设置, 下载一定量的数据到内存, 然后一次过写入到硬盘, 就大大减少了写硬盘的次数.
还有在线视频的缓冲, 都是差不多的机制.
字节缓存流的用法(字符缓存流的用法和字节缓存流一致就不介绍了):
1 | public static void main(String[] args) { |
2 | FileInputStream fis = null; |
3 | FileOutputStream fos = null; |
4 | BufferedInputStream bis = null; |
5 | BufferedOutputStream bos = null; |
6 | try { |
7 | fis = new FileInputStream("D:/javaTest/test1.txt"); |
8 | bis = new BufferedInputStream(fis); |
9 | fos = new FileOutputStream("D:/javaTest/buffTest3.txt"); |
10 | bos = new BufferedOutputStream(fos); |
11 | byte[] bytes = new byte[1024]; |
12 | int len = 0; |
13 | while ((len= bis.read(bytes)) !=-1) { |
14 | System.out.println(new String(bytes,0,len)); |
15 | bos.write(bytes,0,len); |
16 | } |
17 | } catch (IOException e) { |
18 | e.printStackTrace(); |
19 | }finally { |
20 | try { |
21 | //如果有缓冲流,我们只需要关闭缓冲流即可。 |
22 | //fis.close(); |
23 | bis.close(); |
24 | //fos.close(); |
25 | bos.close(); |
26 | } catch (IOException e) { |
27 | e.printStackTrace(); |
28 | } |
29 | } |
30 | } |
31 | } |
上面代码中我们使用了缓存流和文件流,但是我们只关闭了缓存流。这个需要注意一下,当我们使用处理流套接到节点流上的使用的时候,只需要关闭最上层的处理就可以了。java会自动帮我们关闭下层的节点流。
转换流
- InputStreamReader :字节数组转换成字符串。
- OutputStreamWriter:字符串转换成字节数组
转换流的特点:
- 其是字符流和字节流之间的桥梁
- 可对读取到的字节数据经过指定编码转换成字符
- 可对读取到的字符数据经过指定编码转换成字节
解码: 字节数组转字符串
编码:字符串转换成字节数组
字符流和字节流的区别是什么?
- 字符流=字节流+编码集,
- 在实际读取的时候其实字符流还是按照字节来读取,但是会根据编码集进行查找编码集字典解析相应的字节,使得一次读取出一个字符。
- InputStreamReader 继承自Reader ,它本质上是一个字符流,所以可以作为转换流的参数来提高传输效率。
1
java.lang.Object
2
java.io.Reader
3
java.io.InputStreamReader
实例
- 下面以获取键盘输入为例来介绍转换流的用法。
- java使用System.in代表输入。即键盘输入,但这个标准输入流是InputStream类的实例,使用不太方便,而且键盘输入内容都是文本内容,所以可以使用InputStreamReader将其包装成BufferedReader,利用BufferedReader的readLine()方法可以一次读取一行内容,如下代码所示:
1
public static void main(String[] args) throws IOException {
2
InputStreamReader reader = null;
3
BufferedReader bis = null;
4
//System.in 标准输入流是InputStream类的实例,所以需要将其转换为 字节流
5
reader = new InputStreamReader(System.in);
6
bis = new BufferedReader(reader);
7
8
//输出流
9
BufferedWriter buffWriter = null;
10
OutputStreamWriter writer = new OutputStreamWriter(System.out);
11
buffWriter = new BufferedWriter(writer);
12
13
String str;
14
try {
15
while ((str = bis.readLine()) != null){
16
if(StringUtils.equals(str,"exit")){
17
System.exit(1);
18
}
19
System.out.println("输出内容为:" + str);
20
buffWriter.write(str);
21
buffWriter.flush();
22
}
23
}catch (IOException e){
24
e.printStackTrace();
25
}finally {
26
27
}
上面程序将System.in包装成BufferedReader,BufferedReader流具有缓存功能,它可以一次读取一行文本——以换行符为标志,如果它没有读到换行符,则程序堵塞。等到读到换行符为止。运行上面程序可以发现这个特征,当我们在控制台执行输入时,只有按下回车键,程序才会打印出刚刚输入的内容。
对象流
ObjectInputStream/ObjectOutputStream
- 为了让对象持久化(将对象序列化到本地)。可以使用java的对象流处理对象,把对象的内容写到本地存储的文件中,也可以从本地文件中读取出来。也就是常说的序列化和反序列化。
- 使用对象流处理对象进行持久化的顺序是,先创建目标路径,然后创建流通道,之后调用对象流。
1 | /** |
2 | * 序列化:把对象的内容写到本地存储的文件中 |
3 | */ |
4 | public static void serialization(){ |
5 | FileOutputStream fos = null; |
6 | BufferedOutputStream bfs = null; |
7 | ObjectOutputStream oos = null; |
8 | try { |
9 | fos = new FileOutputStream("D:/javaTest/objectTest.txt"); |
10 | bfs = new BufferedOutputStream(fos); |
11 | oos = new ObjectOutputStream(bfs); |
12 | oos.writeObject(new Person("张三",23)); |
13 | } catch (IOException e) { |
14 | e.printStackTrace(); |
15 | }finally { |
16 | try { |
17 | oos.close(); |
18 | } catch (IOException e) { |
19 | e.printStackTrace(); |
20 | } |
21 | } |
22 | |
23 | } |
24 | /** |
25 | * 反序列化:从本地文件中读取对象 |
26 | */ |
27 | public static void deSerialization(){ |
28 | FileInputStream fis = null; |
29 | BufferedInputStream bfs = null; |
30 | ObjectInputStream ois = null; |
31 | try { |
32 | fis = new FileInputStream("D:/javaTest/objectTest.txt"); |
33 | bfs = new BufferedInputStream(fis); |
34 | ois = new ObjectInputStream(bfs); |
35 | Object object = ois.readObject(); |
36 | if(object instanceof Person){ |
37 | System.out.println(JSON.toJSONString(object)); |
38 | } |
39 | } catch (IOException | ClassNotFoundException e) { |
40 | e.printStackTrace(); |
41 | }finally{ |
42 | try { |
43 | ois.close(); |
44 | } catch (IOException e) { |
45 | e.printStackTrace(); |
46 | } |
47 | } |
48 | } |
说明:
本地的文件中的数据(出现乱码),它不是简单的把对象属性值写入IO流中,而是按照一定的数据格式写入的。而这种格式,不是记事本、写字板、Word等文本编辑器能够识别的,因为,这些数据,压根就不是文本数据。只有使用相同版本的Java的ObjectInputStream来进行读取操作
注意:在使用流的时候,注意要清空缓冲区,还有就是最后要关闭流,如果你不想将某些信息存入到磁盘 就可以同过transient关键字修饰成员变量,想要序列化必须要实现Serializable接口,这个接口中没有任何方法,只是标记告诉虚拟机这个类要序列化。