InputStream
859字约3分钟
2024-08-08
InputStream
就是Java标准库提供的最基本的输入流。它位于 java.io
这个包里。java.io
包提供了所有同步 IO
的功能。
InputStream
并不是一个接口,而是一个抽象类,它是所有输入流的超类。这个抽象类定义的一个最重要的方法就是 int read()
,签名如下
public abstract int read() throws IOException;
这个方法会读取输入流的下一个字节,并返回字节表示的 int
值(0~255
)。如果已读到末尾,返回 -1
表示不能继续读取了
FileInputStream
FileInputStream
是 InputStream
的一个子类 FileInputStream
从文件流中读取数据
public static void main(String[] args) throws IOException {
InputStream in = null;
// try ... finally 来保证 InputStream 在无论是否发生 IO 错误的时候都能够正确地关闭
try {
in = new FileInputStream("D:\\marui\\a.txt");
int n;
while ((n = in.read()) != -1) {
System.out.println(n);
}
in.close();
} finally {
if (in != null) {
in.close();
}
}
}
用 try ... finally
来编写上述代码会感觉比较复杂,更好的写法是利用 Java 7
引入的新的 try(resource)
的语法,只需要编写 try
语句,让编译器自动为我们关闭资源
public static void main(String[] args) throws IOException {
try(InputStream in = new FileInputStream("D:\\marui\\a.txt")) {
int n;
while ((n = in.read()) != -1) {
System.out.println(n);
}
}
}
实际上,编译器并不会特别地为 InputStream
加上自动关闭。编译器只看 try(resource = ...)
中的对象是否实现了 java.lang.AutoCloseable
接口,如果实现了,就自动加上 finally
语句并调用 close()
方法。InputStream
和 OutputStream
都实现了这个接口
缓冲
在读取流的时候,一次读取一个字节并不是最高效的方法。很多流支持一次性读取多个字节到缓冲区,对于文件和网络流来说,利用缓冲区一次性读取多个字节效率往往要高很多。InputStream
提供了两个重载方法来支持读取多个字节
int read(byte[] b)
:读取若干字节并填充到byte[]
数组,返回读取的字节数int read(byte[] b, int off, int len)
:指定byte[]
数组的偏移量和最大填充数
public static void main(String[] args) throws IOException {
try(InputStream input = new FileInputStream("D:\\marui\\a.txt")) {
// 定义 1000 字节大小的缓冲区
byte[] buffer = new byte[1000];
int n;
while ((n = input.read(buffer)) != -1) {
System.out.println(n);
}
}
}
利用缓冲区一次读取多个字节时,需要先定义一个 byte[]
数组作为缓冲区,read()
方法会尽可能多地读取字节到缓冲区,但不会超过缓冲区的大小。read()
方法的返回值不再是字节的 int
值,而是返回实际读取了多少个字节。如果返回 -1
,表示没有更多的数据了
阻塞
在调用 InputStream
的 read()
方法读取数据时,read()
方法是阻塞(Blocking
)的
int n;
n = input.read(); // 必须等待read()方法返回才能执行下一行代码
int m = n;
执行到第二行代码时,必须等 read()
方法返回后才能继续。因为读取 IO
流相比执行普通代码,速度会慢很多,因此,无法确定 read()
方法调用到底要花费多长时间
InputStream 实现类
用 FileInputStream
可以从文件获取输入流,这是 InputStream
常用的一个实现类。此外,ByteArrayInputStream
可以在内存中模拟一个 InputStream
public static void main(String[] args) throws IOException {
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);
}
}
}