1 InputStream

InputStream 是字符输入流的基类,按字符将文件或磁盘中的内容读取到内存中。

1.1 使用

InputStream 最重要的方法为 read 方法,读取磁盘内容为字节,并返回字节内容,如果读到末尾,则返回 -1 表示结束。

public abstract int read() throws IOException;

1.1.1 获取流

FileInputStreamInputStream 提供的读取文件流的子类,可以读取这个类通过字节流获取文件内容。

public static void main(String[] args) throws IOException {  
    InputStream inputStream = new FileInputStream("F:\\downloade\\1.txt");  
    for (;;){  
        int read = inputStream.read();  // 反复调用read()方法,直到返回-1
        if (read == -1){  
            break;  
        }  
        System.out.println(read);  //打印byte字节
    }  
    inputStream.close();  //关闭流

1.1.2 关闭流

计算机中,流的开启会占用文件或磁盘资源,如果不关闭资源,JVM 不退出资源无法关闭,程序占用资源会越来越多,影响其他程序的运行。 InputStreamOutputStream 都是用 close 方法关闭流释放底层资源。

在进行 IO 操作时,如果代码过程中发生异常,会导致 close 方法无法执行,资源没有释放,所以需要对 IO 操作进行异常捕获及处理。

public static void main(String[] args) throws IOException {  
    InputStream inputStream = null;  
    try {  
        inputStream = new FileInputStream("F:\\downloade\\1.txt");  
        for (;;){  
            int read = inputStream.read();  
            if (read == -1){  
                break;  
            }  
            System.out.println(read);  
        }  
    } catch (IOException e) {  
        throw new RuntimeException(e);  
    }finally {  
        if (inputStream!= null) {  
            inputStream.close();  
        }  
    }  
}

也可以用 JDK7try(resource) 语法实现:

try(InputStream inputStream1 = new FileInputStream("F:\\downloade\\1.txt")){  
    for (;;){  
        int read = inputStream1.read();  
        if (read == -1){  
            break;  
        }  
        System.out.println(read);  
    }  
}//编译器在此处自动写入finally并调用close方法

原理: 编译器会根据 try(resource) 中对象是否实现了 Closeable 接口,如果实现了该接口,就回自动加上 finally 语句并调用 close 方法。

1.2 缓冲

读取流的时候,按字节读取效率太低,很多流支持一次性将多个字符串读取到缓冲区从而提高效率。InputStream 提供了两个 read 重载方法支持多个字符读取。

  • public int read(byte b[]) throws IOException;//读取若干字节并填充到 byte[] 数组,并返回读取的字节数。
  • public int read(byte b[], int off, int len) throws IOException;//指定 byte[] 数组的偏移量和最大填充数
//缓冲流  
try(InputStream inputStream2 = new FileInputStream("F:\\downloade\\1.txt")){  
    byte[] bytes = new byte[1024];  
  
    while (inputStream2.read(bytes) != -1){  
        System.out.println(new String(bytes));  
    }  
}

1.3 阻塞

InputStreamread 方法是阻塞的,必须完成当前读取操作后才能进行下一个语句。所以执行速度较慢,无法确定 read 方法需要执行多久。

1.4 实现类

1.4.1 FileInputStream

FileInputStream 可以从文件获取输入流,这是 InputStream 常用的一个实现类。

//模拟字节流  
byte[] data = { 72, 101, 108, 108, 111, 33 };  
try (InputStream input = new ByteArrayInputStream(data)) {  
    int n;  
    while ((n = input.read()) != -1) {  
        System.out.println((char)n);  
    }  
}

1.4.2 ByteArrayInputStream

此外,ByteArrayInputStream 可以在内存中模拟一个 InputStream

2 OutputStream

OutputStream (输出字节流) 与 InputStream 相反,是将字符从磁盘中写入到文件中。

2.1 使用

OutputStream 中提供了 write(int b ) 方法写入一个字节到输出流。

2.1.1 写入流

File file = new File("F:\\allFile\\01 temp\\1.txt");  
FileOutputStream outputStream = new FileOutputStream( file);  
outputStream.write(97);  
outputStream.write(98);  
outputStream.write(99);  
//abc

2.1.2 关闭流

OutputStream 也需要对流进行关闭操作,防止资源被占用导致无法复用。

File file = new File("F:\\allFile\\01 temp\\1.txt");  
//abc  
try(FileOutputStream outputStream = new FileOutputStream(file)){  
    outputStream.write(97);  
    outputStream.write(98);  
    outputStream.write(99);  
}

2.1.3 刷新流

输出流提供了 flush() 方法刷新输出流强制写出所有缓冲的输出字节。

在向磁盘、网络写入数据时,出于效率的考虑,操作系统并不是每次 write 操作后将数据写入,而是先把数据存放再缓冲区,等缓冲区域写满后再一次性将数据写入目标设备中。flsh() 方法在进行 close 操作时会自动调用,不必手动调用。

2.2 实现类

2.2.1 FileOutputStream

File file = new File("F:\\allFile\\01 temp\\1.txt");  
 //abcd  
 try(FileOutputStream outputStream = new FileOutputStream(file)){  
     outputStream.write("abcd".getBytes());  
 }

2.2.2 ByteArrayOutputStream

模拟输出流,测试时使用。

ByteArrayOutputStream outputStream = new ByteArrayOutputStream();  
outputStream.write(97);  
outputStream.write(98);  
outputStream.write(99);  
System.out.println(Arrays.toString(outputStream.toByteArray()));