Java 输入输出流


输入输出流表示一个输入来源或一个输出目的地。输入来源和输出目的地包括文件、内存数组、其它程序、网络端口。


一个流是一个数据的序列。程序使用输入流从输入来源读取数据,每次一个数据。程序使用输出流写数据到输出目的地,每次一个数据。

字节流(Byte Stream)

程序使用字节流完成8位字节数据的输入和输出。所有的字节流继承自InputStream和OutputStream。

下面是字节流的例子:

import java.io.FileInputStream;
import java.io.FileOutputStream;

public class ByteStream {
    public static void main(String[] args) {
        FileInputStream in = null;
        FileOutputStream out = null;

        try {
            out = new FileOutputStream("a.txt");
            out.write(0x61);
            out.write(0xe4);
            out.write(0xba);
            out.write(0x8c);

            in = new FileInputStream("a.txt");
            int c;

            while ((c = in.read()) != -1) {
                System.out.println(Integer.toHexString(c));    // 61 e4 ba 8c
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (out != null) {
                try {
                    out.close();
                } catch (Exception e) {
                }
            }
            if (in != null) {
                try {
                    in.close();
                } catch (Exception e) {
                }
            }
        }
    }
}

上面的例子中,从文件中读写时,每次读写都是一个字节。


字符流(Character Stream)

Java内部使用Unicode字符。字符流自动处理Unicode字符和本地字符集之间的互相转换。所有的字符流继承自Reader和Writer。

下面是字符流的例子:

import java.io.FileReader;
import java.io.FileWriter;

public class CharStream {
    public static void main(String[] args) {
        FileReader in = null;
        FileWriter out = null;

        try {
            out = new FileWriter("a.txt");
            out.write('a');
            out.write('二');
            out.flush();

            in = new FileReader("a.txt");
            int c;

            while ((c = in.read()) != -1) {
                System.out.println(Integer.toHexString(c));    // 61 4e8c
                System.out.println((char)c);    // a 二
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (out != null) {
                try {
                    out.close();
                } catch (Exception e) {
                }
            }
            if (in != null) {
                try {
                    in.close();
                } catch (Exception e) {
                }
            }
        }
    }
}

如果在linux上运行上面例子,linux默认的字符编码是utf-8。往文件中写时每次写一个字符,字符'a'写到a.txt文件中的utf-8编码为61,字符'二'写到文件中的utf-8编码为e4ba8c。从文件中读时每次读取一个字符,当读取字符'二'时,java会将utf-8的编码e4ba8c转换成java内部的表示字符的unicode编码0x4e8c

缓冲流(Buffered Stream)

缓存输入流从缓存区(一块内存区域)中读取数据,只有当缓存区中没有数据时,才会调用操作系统的API从输入来源读取数据。缓存输入流向缓存区写入数据,只有当缓存区满了,才会调用操作系统的API向输出目的地写数据。只有操作系统的API才会访问磁盘、网络。缓冲流性能比较好。

通过使用缓冲流包装(wrap)非缓冲流来得到一个缓冲流。例如BufferedReader is = new BufferedReader(new FileReader("a.txt"));。BufferedInputStream和BufferedOutputStream创建缓冲字节流,BufferedReader和BufferedWriter创建缓冲字符流。

调用缓冲输出流的flush方法会将缓存区写入输出目的地,而不用等缓存区满。

下面是字符流的例子:

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;

public class BufferStream {
    public static void main(String[] args) {
        BufferedReader in = null;
        BufferedWriter out = null;

        try {
            out = new BufferedWriter(new FileWriter("a.txt"));
            out.write("cat likes fish\n");
            out.write("dog likes bone");
            out.flush();

            in = new BufferedReader(new FileReader("a.txt"));
            String str;

            while ((str = in.readLine()) != null) {
                System.out.println(str);    // cat likes fish
                // dog likes bone
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (out != null) {
                try {
                    out.close();
                } catch (Exception e) {
                }
            }
            if (in != null) {
                try {
                    in.close();
                } catch (Exception e) {
                }
            }
        }
    }
}

数据流(Data Stream)

数据流支持基本数据类型(byte、char、short、int、long、float、double、boolean)和字符串的二进制输入输出。

下面是数据流的例子:

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.FileInputStream;
import java.io.FileOutputStream;

public class DataStream {
    public static void main(String[] args) {
        DataInputStream in = null;
        DataOutputStream out = null;

        try {
            out = new DataOutputStream(new BufferedOutputStream(new FileOutputStream("a.txt")));
            out.writeInt(1);
            out.writeDouble(0.1);
            out.writeUTF("二");
            out.writeInt(2);
            out.writeDouble(0.2);
            out.writeUTF("中");
            out.flush();

            in = new DataInputStream(new BufferedInputStream(new FileInputStream("a.txt")));
            int i;
            Double d;
            String str;

            try {
                while (true) {
                    i = in.readInt();
                    d = in.readDouble();
                    str = in.readUTF();
                    System.out.format("i = %d, d = %f, str = %s \n", i, d, str);
                        // i = 1, d = 0.100000, str = 二
                        // i = 2, d = 0.200000, str = 中
                }
            } catch (EOFException e) {
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (out != null) {
                try {
                    out.close();
                } catch (Exception e) {
                }
            }
            if (in != null) {
                try {
                    in.close();
                } catch (Exception e) {
                }
            }
        }
    }
}

DataInputStream通过捕获EOFException例外来判断是否end-of-file。

对象流(Object Stream)

对象流支持对象的输入输出。对象流中输出输出的对象需要实现Serializable接口。如果要写入对象a到对象输出流,对象a引用了对象b,对象b引用了对象c,则对象a、b、c都会写入输出流。

下面是对象流的例子:

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class ObjectStream {
    public static void main(String[] args) {
        ObjectInputStream in = null;
        ObjectOutputStream out = null;

        try {
            out = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream("a.txt")));
            out.writeInt(1);
            out.writeObject(new Pet("dog", "bone"));
            out.flush();

            in = new ObjectInputStream(new BufferedInputStream(new FileInputStream("a.txt")));

            int i = in.readInt();
            Pet dog = (Pet) in.readObject();
            System.out.format("i = %d, pet name = %s, food = %s \n", i, dog.name, dog.food);
                // i = 1, pet name = dog, food = bone 
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (out != null) {
                try {
                    out.close();
                } catch (Exception e) {
                }
            }
            if (in != null) {
                try {
                    in.close();
                } catch (Exception e) {
                }
            }
        }
    }
}

class Pet implements Serializable {
    String name;
    String food;

    public Pet(String name, String food) {
        this.name = name;
        this.food = food;
    }
}