Java之IO流
一.流的属性
书上一般说的·都是流的分类,但是我感觉说属性更合适。因为一个流只要存在,那么它就有方向,可操作的最小数据元,有自己的功能。根据这些属性我们就可以准确的定义一个流。(纯属个人理解,如有误望不吝指正)~(^ O^)~
1)输入流、输出流(从流向划分)
Java的输入流主要由InputStream、Reader作为基类;
Java的输出流主要有OutputStream、Writer作为基类。
注意他:们都是抽象类无法直接创建实例
2)字节流、字符流(从操作的数据原划分)
字节流主要由InputStream、OutputStream作为基类,其操作的数据单元是8位的字节;
字符流主要有Reaer、Writer作为基类,其操作的数据单元为两个字节16位的字符。
3)节点流、处理流(从流的功能划分)
节点流又叫低级流,它是直接与数据源(把数据源叫做节点,如磁盘、网络)连接的流;
处理流又叫高级流或者包装流,它将低级流进行二次包装,然后实现数据的读写。
二.流的判断
1)InputStream的子类实现的流一定是输入流、字节流。至于是节点流还是处理流,那就要看它的具体功能了。
2)Reader的子类实现的流一定是输入流、字节流。至于是节点流还是处理流,那就要看它的具体功能了。
注意:我们在研究流的时候其实主要关注它是节点流还是处理流,因为其他类型从它的实现类就可以看出来。
三.流的概念模型
理解流的模型对后面的学习会有很大的帮助。因为Java IO流共涉及40多个类,这些类看上去杂乱繁多,但实际非常有规则,而且彼此之间存在非常紧密的联系。Java IO流的四十多个类都是由InputStream、OutputStream、Writer、Reaer这四个基类派生出来的。
1)输入流、节点流模型
-
模型
输入流模型图 - 例子
public static void main(String[] args) throws IOException {
InputStream in = null;
File f = new File("D:/test.txt");
byte[] b = new byte[2];
in = new FileInputStream(f);//从名字中能分析出那些信息?File代表它直接连接的数据源是File,InputStream指明了它的父类
int i = 0;
while ((i = in.read(b)) != -1) {
String str = new String(b);
System.out.print(str);
}
- 讲解
对于模型的理解书中原话是:输入流使用隐式的记录指针来表示当前当前从哪个水滴开始读取,每当读取一个或多个水滴以后,记录指针会自动往后移。如果是字节流一个水滴代表一个字节,如果是字符流一个水滴代表两个字节。
模型是人们为了方便理解而抽象出来的东西,下面我们结合例子和模型进行理解。
在实例中我们创建了一个FileInputStrea(从名字中我们可以推测出它是一个输入、字节、节点流),它就相当与模型中的那个装满水滴的管道,每个水滴代表一个字节。也就是说FileInputStream这个管道在实例中装的是D:/test.txt这个文件的内容。我们每次读取2个字节,记录指针每次也会跟着移动,我们把管道里的内容读完。
2)输出流、节点流模型
-
模型
当执行输出的时候,程序相当于依次把水滴放入到输出流的管道中,输出流同样采取隐式的记录指针来标识当前水滴的位置,每当程序向管道里放入一个或着多个水滴,记录指针自动后移。
输出流模型图 - 实例
public static void main(String[] args) {
FileOutputStream fop = null;
File file;
String content = "This is the text content";
try {
file = new File("newfile.txt");
fop = new FileOutputStream(file);
// if file doesnt exists, then create it
if (!file.exists()) {
file.createNewFile();
}
// get the content in bytes
byte[] contentInBytes = content.getBytes();
fop.write(contentInBytes);
System.out.println("Done");
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (fop!=null){
fop.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
- 讲解
在实例中创建了FileOutpStream这个空的管道,将内容输出到指定的位置。
3)处理流模型 -
模型
处理流模型图 - 讲解
处理流(包装流)可以包装任何已存在的节点流,包装之后就可以用相同的代码来控制不同的节点流,同时也可以提升效率。
四.节点流
1)所有输入节点流的抽象基类InputStream、Reader
-
InputStream里面包含了如下三个方法:
int read() 从输入流中读取单个字节,返回读取的字节数据(字节数据可直接转换成的int类型)
int read(byte[ ] b) 从流中读取b.length个字节数据,并将其存储在字节数组b中,返回实际读取的字节数
int read(byte[] b,int off,int len) 从流off位置开始,每次最多读取len字节的数据,并放入b字节数组,最后返回实际读取的
void mark(int readAHeadLimit) 记录指针当前位置
boolean markSupported() 判断此输入流是否支持及mark操作
void reset() 将此流的记录指针重新定位到上一次mark的位置
long skip(long n) 将记录指针向前移动n个字节
字节数 -
Reader里面包含的三个方法:
int read() 从输入流中读取单个字符,返回读取的字符数据(字符数据直接转换成的int类型)
int read(char[ ] b) 从流中读取b.length个字符数据,并将其存储在字符数组b中,返回实际读取的字符数
int read(cahr[] b,int off,int len) 从流off位置开始,每次最多读取len字符的数据,并放入b字符数组,最后返回实际读取的字符数
void mark(int readAHeadLimit) 记录指针当前位置
boolean markSupported() 判断此输入流是否支持及mark操作
void reset() 将此流的记录指针重新定位到上一次mark的位置
long skip(long n) 将记录指针向前移动n个字符
2)所有输出节点流的基类OutputStream、Writer
3) 实现节点流的类
五.处理流
识别处理流的方法,只要流的构造参数不是一个物理节点,而是一个已存在的流,那这种流一定是处理流。处理流的优点前面已经说过了操作简单,效率更高。
1) 管道流 实现进程之间的通信功能
2)缓冲流 缓冲流具有缓冲功能,增加缓冲功能后需要flush()才可以将缓冲区的内容写入物理节点,该功能对大幅度的提高了读写效率。
好多人写代码的时候都喜欢在最后把流fush 然后再close。close是必须的,但是flush有时候是可以不写的,如果你查看了没有缓冲功能的流,你会发现其实它们的flush()方法为空。
为什么缓冲流可以提升读写效率呢?举个例子,假如你去超市买东西,你是不是会推一个小推车,然后把选好的东西放车里,最后一块儿去付款。你肯定不会拿一件然后去收银台付一次款,拿一件然后付一次。缓冲区就是这个小推车,如果你买的东西多一车不够,可以多来两趟,那个收银台就是物理节点。
3)转换流
文件通常被分为文本文件和二进制文件,所有能用记事本打开并看到字符内容(非乱码)的文件称为文本文件(它是特殊的二进制文件),反之则成为二进制文件。
转换流是把字节流转换成了字符流,如果能确定一个字节流是纯文本文件,那么把它转换成字符流更容易操作。