java I/O体系总结

java I/O体系总结

I/O流的理解

先看看流的概念

流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象。即数据在两设备间的传输称为流,流的本质是数据传输,根据数据传输特性将流抽象为各种类,方便更直观的进行数据操作。

通俗的说,有两个文件A和B,想要把A的内容拷贝到B中,可以假设两文件间有一个通道,把A的数据按字节或是字符的形式传送给B。这个通道就是java I/O体系流的概念,即可以把流当做抽象的通道。

理解了流的概念,流的分类也就很好明白了。以流的方向来说,流从外界(网络或磁盘)读取到程序(内存)中,就是输入流。流从程序流向外界就是输出流。

这里写图片描述

基础的流

流又可按传输的数据类型分为字节流和字符流。简单理解就是传输是二进制的字节(字节流)还是直接可以看懂的字符(字符流)。结合输入输出流,java的I/O流基础的类(接口)主要有以下几个:

  1. InputStream(输入字节流)
  2. OutputStream(输出字节流)
  3. Reader(输入字符流)
  4. Writer(输出字符流)

关于字节流

字节流是最基本的I/O处理流,之所以基本,是因为所有形式的储存(文件,磁盘或网络)底层都是以字节形式存储的。InputStream是所有字节输入流的父类,OutputStream是所有字节输出流的父类。字节流主要用于处理二进制数据。处理单位主要是字节或字节数组。

关于字符流

鉴于有些文件是以文本存储的,为方便操作,于是有了字符流。字符流主要用于处理字符或字符串。每个字符占两个字节。在实现上,字符流即由java虚拟机将字节转为字符(每2个字节转为一个字符)形成的。字符输入流的父类是Writer,字符输出流的父类是Reader。

示例

其他流都是基于以上4个基础接口做的扩展及实现。就以文件传输为例,传输类型为字节,则有FileInputStream(文件输入流)和FileOutputStream(文件输出流)。看下示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

/**
* 输入流测试
* 将磁盘中的文件读取到内存中,以字节的形式
* 要读取的文件为hello.txt,其中内容为"hello,world"
*/
@Test
public void testInputStream() throws Exception {
InputStream inputStream = null;
try {
//代表磁盘文件
File file = new File("/Users/wangtonghe/local/tmp/hello.txt");
// 构建输入流
inputStream = new FileInputStream(file);
int b = 0;
// 获取到流的内容
while ((b = inputStream.read()) != -1) {
// 输出流的内容
System.out.println((b);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
if (inputStream != null) {
inputStream.close();
}
}
}

上面这个示例很简单,就是将待操作文件包装到文件输入流中,读取到内存。

看一个整体的示例吧,字符类型的文件输入输出。将a.txt的内容拷贝到b.txt中。FileWriter表示文件字符输出类,FileReader表示文件字符输入类。

一般的做法是,将a.txt包装到文件输入流,读取到内存。再通过文件输出流输出到b.txt文件中。

用图表述即为

这里写图片描述

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

@Test
public void testFile() throws Exception {

File aFile = new File("/Users/wangtonghe/local/tmp/a.txt");
File bFile = new File("/Users/wangtonghe/local/tmp/b.txt");

FileReader reader = null;
FileWriter writer = null;

try {
// 构建文件输入流
reader = new FileReader(aFile);
// 构建文件输出流
writer = new FileWriter(bFile);
char[] chars = new char[1024];
int len = 0;
// 读取输入流
if ((len = reader.read(chars)) != -1) {
//写入输出流
writer.write(chars, 0, len);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (reader != null) {
reader.close();
}
if (writer != null) {
writer.close();
}
}
}

字节流与字符流的区别

  1. 操作对象不同,这是最基本的区别。字节流操作字节或字节数组;字符流操作字符或字符串。
  2. 字节流对终端(文件等)直接进行操作,而字符流使用缓冲区(即先把数据写入缓存区,再对缓存区进行操作)
  3. 由于2的存在,对字节的操作会直接影响终端(文件)结果,而对字符流的操作最后必须关闭流或强制刷新流才能写入数据,否则只是写到了缓存区,文件等终端不受影响。
  4. 详见 java 字节流与字符流的区别

两种流的相互转化

InputStreamReader以及OutputStreamWriter 负责两种流的相互转换。(一般是字节流转字符流,没有字符转字节,也不需要)

InputStreamReader可以将字节输入流转为字符输入流;OutputStreamWriter可以将字节输出流转为字符输出流。

转化过程如下:

1
2
3
4
5
6
7

//文本文件
File aFile = new File("/Users/wangtonghe/local/tmp/a.txt");
// 文件字节流
FileInputStream fileInputStream = new FileInputStream(aFile);
// 字节流转为字符流
Reader reader = new InputStreamReader(fileInputStream);

转化流构造方法及用法如下

  1. InputStreamReader(InputStream); //通过构造函数初始化,使用的是本系统默认的编码表GBK。
  2. InputStreamWriter(InputStream,String charSet); //通过该构造函数初始化,可以指定编码表。
  3. OutputStreamWriter(OutputStream); //通过该构造函数初始化,使用的是本系统默认的编码表GBK。
  4. OutputStreamwriter(OutputStream,String charSet); //通过该构造函数初始化,可以指定编码表

I/O流概览

这里写图片描述

java体系I/O流大致类及结构就如上图所示。

简要介绍一下

输入字节流InputStream

  1. InputStream 是所有的输入字节流的父类,它是一个抽象类。
  2. ByteArrayInputStream、StringBufferInputStream、FileInputStream 是三种基本的介质流,它们分别从Byte数组、StringBuffer、和本地文件中读取数据。
  3. ObjectInputStream 和所有FilterInputStream 的子类都是装饰流(装饰器模式的主角)。

同理输出字节流OutputStream与此类似

  1. OutputStream 是所有的输出字节流的父类,它是一个抽象类。
  2. ByteArrayOutputStream、FileOutputStream 是两种基本的介质流,它们分别向Byte 数组、和本地文件中写入数据。
  3. ObjectOutputStream 和所有FilterOutputStream 的子类都是装饰流。

I/O体系的装饰器模式

关于I/O体系,一定要谈的就是其装饰器的设计模式。

装饰器模式

概念 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。它能让我们在扩展类的时候让系统较好的保持灵活性。

这里就不具体介绍装饰器模式了,可以看看Java设计模式12:装饰器模式

java I/O中实现装饰器模式主要由FilterInputStream及其子类(输入流)和FilterOutputStream及其子类完成。

如BufferedInputStream,有缓冲功能的输入流,可修饰FileIntputStream使其拥有缓冲功能。

BufferedInputStream bis = new BufferedInputStream(new FileInputStream(new File(“/home/user/abc.txt”)));

参考文章

  1. java 字节流与字符流的区别
  2. 字节流与字符流的区别详解
  3. Java IO流学习总结一:输入输出流
  4. Java设计模式12:装饰器模式
  5. Java IO : 流,以及装饰器模式在其上的运用
分享到:
0%