目录
到目前为止,使用的字节流、字符流都是无缓冲的输入、输出流,这就意味着,每次的读、写操作都会交给操作系统来处理。这样的做法可能会对系统的性能造成很大的影响,因为每次操作都可能引发磁盘硬件的读、写或网络的访问,这些磁盘硬件读、写和网络访问会占用大量系统资源,影响效率。而接下来要介绍的一些流就可以很好的解决这一问题。
1.装饰器模式简介
缓冲流、转换流和数据流等,其底层都遵循着一个相同的设计模式——装饰器模式
简单的讲,装饰器模式就是通过方法,将对象逐步进行包装。例如,字节输出流 FileOutputStream
对象放在缓冲输出流 BufferedOutputStream
类的构造方法中以后,就变成了一个缓冲输出流 BufferedOutputStream
对象:
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(...)) ;
更进一步,缓冲输出流对象如果又被传入到了数据流 DataOutputStream
类的构造方法中,就又变成了一个数据流 DataOutputStream
对象:
DataOutputStream out = new DataOutputStream(bos);
注意的是,装饰器模式在语法上要求包装类和被包装类属于同一个继承体系,并且包装后外观(API)未变,但功能得到了增强
2.缓冲流
缓冲流的目的是让原字节流、字符流新增缓冲的功能。以字符缓冲流为例进行说明,字符缓冲流从字符流中读取、写入字符,不立刻要求系统进行处理,而是缓冲部分字符,从而实现按规定字符数、按行等方式的高效读取或写入。缓冲区的大小可以指定(通过缓冲流构造方法指定),也可以使用默认的大小,多数情况下默认大小已够使用
import java.io.*;
public class TestBufferStream {
public static void main(String[] args) throws IOException {
BufferedReader in = null;
BufferedWriter out = null;
try {
in = new BufferedReader(new FileReader("/home/project/ori_file.txt"));
out = new BufferedWriter(new FileWriter("/home/project/new_file.txt"));
//逐行读取、存入字符串,实现文件复制
String s;
while ((s = in.readLine()) != null) {
out.write(s);
//写入一个分行符,否则内容在一行显示
out.newLine();
}
} catch (IOException e) {
System.out.println(e.getMessage());
} finally {
if (in != null) {
in.close();
}
if (out != null) {
out.close();
}
}
}
}
上面的代码中,在读取数据时,使用的是 BufferedReader
缓冲流的 readLine()
方法,获取该行字符串并存储到 String
对象 s
里。在输出的时候,使用的是 BufferedWriter
缓冲流的 write(s)
方法,把获取的字符串输出到 new_file.txt
文件。有一个地方需要注意,在每次调用 write(s)
方法之后,要调用输出缓冲流的 newLine()
方法写入一个分行符,否则所有内容将在同一行显示。 有些情况下,不是非要等到缓冲区满,才向文件系统写入。例如在处理一些关键数据时,需要立刻将这些关键数据写入文件系统,这时则可以调用 flush()
方法,手动刷新缓冲流(即,将缓冲区中的数据强行从内存中清理到硬盘等其他地方)。另外,在关闭流时,也会自动刷新缓冲流中的数据,即 close()
方法会自动调用 flush()
方法。
flush()
方法的作用就是刷新该流的缓冲。如果该流已保存缓冲区中各种 write()
方法的所有字符,则立即将它们写入预期目标。如果该目标是另一个字符或字节流,也将其刷新。因此,一次 flush()
调用将刷新 Writer
和 OutputStream
链中的所有缓冲区。
3.转换流
要把一个字节流转换成一个字符流,可以使用 InputStreamReader
和 OutputStreamWriter
这两个类来进行转换
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class TestByteToChar {
public static void main(String[] args) throws IOException {
BufferedReader in = null;
try {
//将字节流System.in通过InputStreamReader转换成字符流
in = new BufferedReader(new InputStreamReader(System.in));
System.out.print("请输入你今天最想说的话:");
String s = in.readLine();
System.out.println("你最想表达的是:" + s);
} catch (IOException e) {
System.out.println(e.getMessage());
} finally {
if (in != null) {
in.close();
}
}
}
}
4.数据流
数据流,简单来说就是允许流直接操作基本数据类型和字符串
import java.io.*;
public class TestData{
static final String dataFile = "/home/project/data";//数据存储文件
//标识车类型:1代表轿车、2代表卡车
static final int[] types = {1,1,2,2};
static final String[] names = { "战神","跑得快","大力士","大力士二代"};
static final int[] oils = {20,40,20,30};
static final int[] losss = {0,20,0,30};
static final String[] others = { "长城","红旗","5吨","10吨"};
static DataOutputStream out = null;
static DataInputStream in = null;
public static void main(String[] args) throws IOException {
try {
//输出数据流,向dataFile输出数据
out = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(dataFile)));
for (int i = 0; i < types.length; i++) {
out.writeInt(types[i]);
//使用UTF-8编码将一个字符串写入基础输出流
out.writeUTF(names[i]);
out.writeInt(oils[i]);
out.writeInt(losss[i]);
out.writeUTF(others[i]);
}
}finally {
out.close();
}
try{
int type,oil,loss;
String name,other;
//输出数据流,从dataFile读出数据
in = new DataInputStream(new BufferedInputStream(new FileInputStream(dataFile)));
while(true)
{
type = in.readInt();
name = in.readUTF();
oil = in.readInt();
loss = in.readInt();
other = in.readUTF();
if(type == 1){
System.out.println("显示车辆信息:\n车型:轿车 车辆名称为:" + name +
" 品牌是:" + other + " 油量是:" + oil + " 车损度为:" + loss);
}else{
System.out.println("显示车辆信息:\n车型:卡车 车辆名称为:" + name +
" 吨位是:" + other + " 油量是:" + oil + " 车损度为:" + loss);
}
}
}catch(EOFException e){
//EOFException作为读取结束的标志
}finally {
in.close();
}
}
}