1 基本概念
- Java把不同类型的输入、输出源抽象为流(stream),其中输入或输出的数据称为数据流(Data Stream),用统一的接口来表示。
- Java中的io是实现输入和输出的基础,可以方便的实现数据的输入和输出操作。
- Java把所有的流类型代码都放在java io包下,用于实现输入和输出功能。
2 分类
2.1输入流和输出流
按照流的流向划分,可以分为输入流和输出流。 注意,流向是以内存(程序)的角度来划分的,输入到内存(程序)的就是输入流,从内存(程序)输出的就是输出流,如下图:
2.1.1输入流
Java的输入流主要是InputStream和Reader作为基类。它们都是一些抽象基类,无法直接创建实例。 对于输入流来说,它们把输入设备抽象为一个“水管”,这个水管的每个“水滴”依次排列。如下图: 操作位置由隐式的记录指针决定,取出数据后记录指针会自动移动,同时也提供了方法操作记录指针。 字节流和字符流的处理方式是一样的,只是他们的输入/输出单位不同而已,字节流的单位是字节,字符流的单位是字符。
2.1.2输出流
Java的输出流主要是OutputStream和Writer作为基类。它们都是一些抽象基类,无法直接创建实例。 对于输出流来说,它们同样把输出设备抽象为一个“水管”,只是这个水管中没有“水滴”。如下图: 操作位置由隐式的记录指针决定,输出的“水滴”放置后,记录指针自动移动,同时也提供了方法操作记录指针。 字节流和字符流的处理方式是一样的,只是他们的输入/输出单位不同而已,字节流的单位是字节,字符流的单位是字符。
2.2字节流和字符流
按照操作单元划分,可以分为字节流和字符流。 字节流主要是由InputStream和OutputStream作为基类,而字符流主要是Reader和Writer作为基类。 字节流和字符流的区别:
- 读写单位不同:字节流以字节(8bit)为单位,字符流以字符为单位,根据码表映射字符,一次可能度多个字节。
- 处理对象不同:字节流能处理所有类型的数据(如图片、avi等),而字符流只能处理字符类型的数据。
- 二进制位数:字节流一次操作的是8位二进制,而字符流一次操作的是16位二进制。
- 中文处理:字节流以字节为单位,故无法处理中文(因一个中文占两个字节)。但字符流可以处理。
- 缓冲区:字节流是直接对文件进行处理,而字符流存在缓冲区,所有操作在缓冲区完成后再对文件进行处理。
3.类图
3.1基类
红色底线,是所有输入/输出流的父类,是一个抽象类。 InputStream/Reader:所有的输入流的基类,前者是字节输入流,后者是字符输入流。 OutputStream/Writer:所有的输出流的基类,前者是字节输出流,后者是字符输出流。
3.2节点流
橙色底线,直接与数据源相连,读入或读出。 直接使用节点流,读写不方便,为了更快的读写文件,才有了处理流。 常用的节点流:
- 文件处理:FileInputStream、FileOutputStream、FileReader、FileWriter。
- 数组处理:ByteArrayInputStream、ByteArrayOutputStream、CharArrayReader、CharArrayWriter。
- 字符串处理:StringReader、StringWriter。
- 多线程管道通信:PipedInputStream、PipedOutputStream、PipedReader、PipedWriter。
注意,FilterInputStream和FilterOutputStream使用的是设计模式中的装饰器模式。
3.3处理流
处理流和节点流一块使用,在节点流的基础上,再套接一层,套接在节点流上的就是处理流。处理流的构造方法总是要带一个其他的流对象做参数。一个流对象经过其他流的多次包装,称为流的链接。 处理流可细分为: 1、缓冲流,绿色底线,增加缓冲功能,避免频繁读写硬盘。常用的有BufferedInputStream、BufferedOutputStream、BufferedReader、BufferedWriter。 2、转换流,紫色底线,实现字节流和字符流之间的转换。常用的有InputStreamReader、OutputStreamReader。 3、数据流,黑色底线,提供将基础数据类型写入或读取到文件中。常用的有DataInputStream、DataOutputStream。
4.示例
字节流FileInputStream和缓冲流BufferedInputStream读取文件内容代码:
public String filePrint(String filePath){
File targetFile = new File(filePath);
BufferedInputStream bufFis = null;
StringBuilder stringBuilder = new StringBuilder();
try {
bufFis = new BufferedInputStream(new FileInputStream(targetFile));
int size = bufFis.available();
byte[] buf = new byte[size];
int hasRead = 0;
while((hasRead = bufFis.read(buf)) != -1){
String fileStr = new String(buf,0,hasRead);
stringBuilder.append(fileStr);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally{
if(bufFis != null){
try {
bufFis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return stringBuilder.toString();
}
字节流FileOutputStream和缓冲流BufferedOutputStream写入文件内容代码:
public void fileWrite(String filePath,String fileMsg){
BufferedOutputStream buffFos = null;
try {
buffFos = new BufferedOutputStream(
new FileOutputStream(new File(filePath),true));
byte[] data = fileMsg.getBytes();
buffFos.write(data,0,data.length);
buffFos.flush();
System.out.println("文件写入成功!!");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{
if(buffFos != null){
try {
buffFos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
5.注意事项
在实际的项目中,所有的IO操作都应该放到子线程中操作,避免堵住主线程。
6.参考文献
Java IO流学习总结一:输入输出流
|