JAVA输入/输出流体系中常用的流分类
分类 | 字节输入流 | 字节输出流 | 字符输入流 | 字符输出流 |
---|---|---|---|---|
抽象基类 | InputStream | OutputStream | Reader | Writer |
访问文件 | FileInputStream | FileOutputStream | FileReader | FileWriter |
访问数组 | ByteArrayInputStream | ByteArrayOutputStream | CharArrayReader | CharArrayWriter |
访问管理 | PipedInputStream | PipledOutputStream | PipledReader | PipledWriter |
访问字符串 | StringReader | StringWriter | ||
缓冲流 | BufferedInputStream | BufferedOutputStream | BufferedReader | BufferedWriter |
转换流 | InputStreamReader | OutputStreamWriter | ||
对象流 | ObjectInputStream | ObjectOutputStream | ||
抽象基类 | FilterInputStream | FilterOutputStream | FilterReader | FilterWriter |
打印流 | PrintStream | PrintWriter | ||
推回输入流 | PushbackInputStream | PushbacKReader | ||
特殊流 | DataInputStream | DataOutputStream |
流的分类
- 按照流的流向来分类,可以分为输入流和输出流。这里的输入输出均是从程序运行的内存来划分的。
- 字节流和字符流。字节流操作的数据单元为8个字节,而字符流操作的数据单元为16个字节。字节流的主要是以InputStream 和 OutputStream为基类,而字符流主要是以Reader和Writer为基类。
- 按照流的角色来看,可分为节点流和处理流。节点流直接连接到实际的数据源,处理流则是对已有的节点流进行封装或连接。
对文件的操作
对文件的操作主要采用FileInputStream和FileOutputStream, FileReader和FileWriter这4类来进行读写操作,区别就在于操作数据的的单元。以下在的代码做参考。
import java.io.*;
public class FileOperation{
public static void main(String[] args){
try{
//创建一个指向本文件的输入流
FileInputStream fis = new FileInputStream("FileOperation.java");
//创建一个指向back.bat的输出流
FileOutputStream fos = new FileOutputStream("back.bat");
{
//创建一个长度为32的"竹筒“
byte[] bbuf = new byte[32];
//用于保存实际读取的字节数
int hasRead = 0;
//使用循环来重复的进行读取操作
while((hasRead = fis.read(bbuf)) > 0) {
fos.write(bbuf, 0, hasRead);
}
}
fis.close();
fos.close();
}
catch (IOException ioe){
System.out.println("文件没有找到");
}
}
}
运行此代码会发现在路径下多了一个back.bat文件,里面的内容与FileOperation.java完全相同。
数据处理
在实际中可能会碰到这样的一个问题,比如把double, boolean这一类的数据写到文件或者或者地方。这时候就需要使用到DataInputStram和DataOutputStream这两个类。
以下的代码体现了这样一种方法。
import java.io.*;
public class DataTest{
public static void main(String[] args) throws IOException{
DataOutputStream dos = new DataOutputStream(new FileOutputStream("data.bat"));
DataInputStream dis = new DataInputStream(new FileInputStream("data.bat"));
dos.writeDouble(Math.random());
dos.writeChar('A');
double d = (double) dis.readDouble();
char c = (char) dis.readChar();
System.out.println(d);
System.out.println(c);
}
}
在以上代码中,将一个随机double及一个char采用DataOutputStream分别写入到data.bat文件当中,然后再采用DataInputStream分别读出。这样可以很方便的对double, int, char, float类型进行流入流出。
但这个方法有一个不好在于保证流入与流出的类型及先后顺序相同,如上一例中先流出double 类型,再写入char类型,流入的类型也要与之相对应,即先入先出,并且类型相同,如果顺序或者类型不同,则会带来前面数据的不统一。
缓冲流
缓冲流可以提高效率,类似去接水,InputStream 是一滴一滴水的接,而bufferedStream是一桶一桶的接。一次性读入多个多个数据至内存中,然后再进行操作,一方面可以提高效率,一方面可以减少对硬盘的读写,减少对硬盘的损伤。具体的代码在这里就不写了,缓冲流为处理流,需要 套在节点流或者其他流上进行操作。
转换流
InputStreamReader, OutputStreamWriter 由类名可以看到前面是stream,后面是reader/writer,将字节流转换为字符流,以便进行更方便的操作。常用的操作将字节流转换为字符流,然后后面再套上BufferedReader或者BufferWriter来进行读写。因为BufferedReader和BufferWriter里面有readLine(), writerLine()方法,可以针对每行来进行读写,读写效率非常高。
import java.io.*;
public class StreamReaderTest{
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("StreamReaderTest.java");
InputStreamReader isr = new InputStreamReader(fis);
BufferedReader br = new BufferedReader(isr);
System.out.println(br.readLine());
}
}
以上代码体现了InputStreamReader的用法,在InputStreamReader包装了FileInputStream,后面包装了BufferedReader,然后使用readLine()方法,可以一次读入一行。效率提高。
对象流
对象流主要是针对对象来进行读写操作,比如有一个Person对象,对象里面有一些属性及方法,那这些属性及方法如果进行流入流出,则需要使用对象流。对象流只有两个方法ObjectInputStream和ObjectOutputStream, 均为处理流,需要包装InputStream及OutputStream来使用。
import java.io.*;
//读写的对象需要实现Serializable接口。
class Person implements Serializable{
int age;
String name;
public Person(String name, int age){
this.name = name;
this.age = age;
}
public void setAge(int age){
this.age = age;
}
public int getAge(){
return age;
}
}
public class ObjectClassTest{
public static void main(String[] args) throws IOException, ClassNotFoundException{
Person p1 = new Person("Tom", 25);
//新建一个ObjectOutputStream, 套在FileOutputStream节点流上,可以将Object与入到文件中
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("person.txt"));
//从上面的文件中读入Object
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("person.txt"));
//将P1写入person.txt文件当中。
oos.writeObject(p1);
//readObject 的返回值类型为Object,在这里面需要进行强制类型转换。
Person p2 = (Person) ois.readObject();
//读入的类型同样读入了类的方法
System.out.println(p2.getAge());
//可以对类的属性进行更改
p2.name = "Jim";
System.out.println(p2.name);
}
}
如上代码就实现在Object类型的流入流出。