Java中的I/O流系统(一):字节流体系知识总结

I/O流是指从计算机的外设和程序之间传送的数据序列;输入流代表从计算机外设流入程序的数据序列,如通过键盘输入的数据;输出流代表从程序流向计算机外设的数据序列,如向屏幕打印数据。根据I/O流数据格式分类可以将I/O流分为字节流和字符流,本篇主要介绍字节流。

字节I/O流简要体系

在这里插入图片描述


原始字节流

FileInputStream

1. 构造方法

构造方法说明
FileInputStream(String name)输入流关联文件,文件路径以字符串形式给出
FileInputStream(File file)输入流关联文件,文件路径以File对象形式给出

关联的文件如果不存在就会抛出FileNotFoundException异常,路径如果是一个文件夹会提示拒绝访问。

2. 常用成员方法

成员方法说明
int read()从数据中读入一个字节,并返回该字节,碰到输入流结尾时返回-1
int read(byte[] b)读入一个字节数组,返回实际读入的字节数,碰到输入流结尾时返回-1,最多读入b.length个字节
void close()关闭这个输入流

当完成输入/输出流的读写时,应该调用close方法来关闭它,以释放掉十分有限的操作系统资源。

在JDK7版本以后,可以使用将需要调用close方法的对象放到try()的括号里面,将在代码块结束后自动关流。try()中的对象需要实现过AutoCloseable接口。

FileOutputStream

1. 构造方法

构造方法说明
FileOutputStream(String name)输出流关联文件,文件路径以字符串形式给出
FileOutputStream(String name, boolean append)append若为Ture表示允许追加
FileOutputStream(File file)输出流关联文件,文件路径以File对象形式给出
FileOutputStream(File file, boolean append)append若为Ture表示允许追加

2. 常用成员方法

成员方法说明
void write(int b)写出单个字节
void write(byte[] b)写出一个字节数组
void write(byte[] b, int off, int len)写出从off开始len长范围内的字节数组内容
void close()冲刷并关闭输出流
void flush()冲刷输出流将缓冲数据发送到目的地

write()方法括号内放的是字节,对于非字节内容的输出可以使用getBytes()将内容转化为字节或字节数组进行输出。

关闭一个输出流的同时还会冲刷用于该输出流的缓冲区,所有被临时置于缓冲区以便用更大的包的形式传递的字节在关闭输出流是将会被送出。当然也可以用flush方法人为地冲刷写出字节的最后一个包的输出。

//读入和写出单个字节
try(FileInputStream fis1=new FileInputStream("E:\\Test1.jpg");
    FileOutputStream fos1=new FileOutputStream("E:\\Test1New.jpg")){
    int b;
    while((b=fis1.read())!=-1){
        fos1.write(b);
    }
} catch (IOException e){
    e.printStackTrace();
}

//读入和写出字节数组
try(FileInputStream fis2=new FileInputStream("E:\\Test2.jpg");
    FileOutputStream fos2=new FileOutputStream("E:\\Test2New.jpg")) {
    int len;
    byte[] bytes=new byte[1024*8];
    while((len=fis2.read(bytes))!=-1){
        fos2.write(bytes,0,len);
    }
} catch(IOException e){
    e.printStackTrace();
}

缓冲字节流

BufferedInputStream和BufferedOutputStream采用缓冲区(内置数组8192字节)来读写数据,以减少读写次数从而加快输入输出速度,提高处理效率。

缓冲流不具备读写功能,它们只是对普通的流对象进行包装,在流中增加了一个缓冲区。缓冲字节流本身并没有增添什么新方法,真正和文件建立关联的,还是普通的流对象。

BufferedInputStream

带缓冲区的输入流在从流中读入字符时,不会每次都访问设备。当缓冲区为空时,会向缓冲区中再读入一个新的数据块。

构造方法说明
BufferedInputStream(InputStream in)创建一个带缓冲区的输入流

BufferedOutputStream

带缓冲区的输出流在收集要写出的字符时,不会每次都访问设备。当缓冲区填满或当流被冲刷时,数据就被写出。

构造方法说明
BufferedInputStream(InputStream in)创建一个带缓冲区的输出流
//使用缓冲流进行读入和写出
try(BufferedInputStream bis=new BufferedInputStream(new FileInputStream("E:\\test.jpg"));
    BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream("E:\\testNew.jpg"))){
    int b;
    while((b=bis.read())!=-1){
        bos.write(b);
    }
} catch(IOException e){
    e.printStackTrace();
}

在进行文件输入和输出时,一般选择使用原始字节流读取字节数组或直接使用缓冲字节流。


字节打印流

打印流可以实现更方便、更高效的打印数据出去。

PrintStream

1. 构造方法

构造方法说明
PrintStream(File file)打印流通向文件
PrintStream(File file, Charset charset)打印流通向文件,允许指定编码方式
PrintStream(OutputStream out)打印流通向字节输出流
PrintStream(String fileName)打印流通向文件路径
PrintStream(String fileName, Charset charset)打印流通向文件路径,允许指定编码方式
  1. 构造方法中还有一种在参数中加入一个布尔变量指定实现自动刷新。如果没有使用到缓冲区,就不需要使用flush。只有使用了Buffer的才需要flush。

  2. PrintStream本身不能实现追加,可以使用FileOutputStream输出流实现追加。

2. 常用成员方法

成员方法说明
void println(XXX xxx)打印任意类型的数据出去

printStream继承自FilterOutputStream,继承自OutputStream,父类的write()等方法也可以使用。

try(PrintStream ps=new PrintStream("E:\\text.txt")){
    ps.println(97);        //结果为97
    ps.println('a');       //结果为a
    ps.println(true);      //结果为true
    ps.write(97);          //结果为a
} catch(IOException e){
    e.printStackTrace();
}

3. 输出语句的重定向

在实际的软件开发过程中,很少会将语句输出到控制台,而是保存到某个文件中,可以把输出语句的打印位置改到某个文件中去。

try(PrintStream ps=new PrintStream("E:\\text.txt")){
    System.setOut(ps);
    System.out.println("这句话会输入到文件中");
} catch(IOException e){
    e.printStackTrace();
}

数据流

DataInputStream

数据输入流用于读取数据输出流写出的数据。

1. 构造方法

构造方法说明
public DataInputStream(InputStream in)创建一个DataInputStream包装基础的字节输入流

2. 常用成员方法

成员方法说明
byte readByte()读入一个字节类型的值
char readChar()读入一个字符类型的值
double readDouble()读入一个双精度浮点类型的值
int readInt()读入一个整型类型的值
String readUTF()读入由“修订过的UTF-8”格式的字符构成的字符串

DataOutputStream

数据输出流允许把数据和其类型一并写出去。

1. 构造方法

构造方法说明
public DataOutputStream(OutputStream out)创建一个DataOutputStream包装基础的字节输出流

2. 常用成员方法

成员方法说明
void writeByte(int b)写出一个字节类型的值
void writeChar(int c)写出一个字符类型的值
void writeDouble(double d)写出一个双精度浮点类型的值
void writeInt(int i)写出一个整型类型的值
void writeChars(String s)写出字符串中的所有字符
void writeUTF(String s)写出由“修订过的UTF-8”格式的字符构成的字符串

除了表格中的成员方法,类似的还可以读入和写出boolean、float、long、short等类型的数据。

//使用数据输出流
try(DataOutputStream dos=new DataOutputStream(new FileOutputStream("E:\\data1.txt"))){
    dos.writeByte(97);
    dos.writeChar('a');
    dos.writeDouble(9.7);
    dos.writeInt(97);
    dos.writeUTF("专业开发者社区");
} catch (IOException e){
    e.printStackTrace();
}

//使用数据输入流
try(DataInputStream dis=new DataInputStream(new FileInputStream("E:\\data1.txt"))){
    System.out.println(dis.readByte());
    System.out.println(dis.readChar());
    System.out.println(dis.readDouble());
    System.out.println(dis.readInt());
    System.out.println(dis.readUTF());
} catch (IOException e){
    e.printStackTrace();
}

序列化流

ObjectInputStream

可以把Java对象进行反序列化,即把存储在文件中的Java对象读入到内存中来。

1. 构造方法

构造方法说明
ObjectInputStream(InputStream in)创建一个ObjectInputStream用于从指定的Input中读回对象信息

2. 常用成员方法

成员方法说明
Object readObject()把存储在文件中的Java对象读出来

ObjectOutputStream

可以把Java对象进行序列化,即把Java对象存入到文件中去。

1. 构造方法

构造方法说明
ObjectOutputStream(OutputStream out)创建一个ObjectOutputStream用于将对象写出到指定的OutputStream

2. 常用成员方法

成员方法说明
void writeObject(Object obj)写出指定的Java对象

对象如果要参与序列化,必须实现序列化接口java.io.Serializable。如果要使成员属性变量不被序列化可以在类中用transient关键字修饰该变量。

如果要一次序列化多个对象,可以使用一个ArrayList集合存储多个对象,然后直接对集合进行序列化(ArrayList集合已经实现序列化接口)。

//使用对象输出流
try(ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("E:\\object.txt"))){
    Person person1=new Person("张三","男",20);
    oos.writeObject(person1);
} catch (Exception e){
    e.printStackTrace();
}

//使用对象输入流
try(ObjectInputStream ois=new ObjectInputStream(new FileInputStream("E:\\object.txt"))){
    System.out.println((Person)ois.readObject());
} catch (Exception e){
    e.printStackTrace();
}