Java InputStream 类
最后修改时间:2025 年 4 月 16 日
java.io.InputStream 类是一个抽象超类,表示字节的输入流。它是 Java 中所有字节输入流的基础。具体的子类实现了特定的输入源,例如文件、网络连接或内存缓冲区。
InputStream 提供了从各种源读取字节的基本方法。它支持基本的读取操作、流标记、跳过和资源管理。所有方法都会在发生 I/O 错误时抛出 IOException。
InputStream 类概述
InputStream 是一个抽象类,它定义了读取字节的核心功能。主要方法包括各种读取操作、流控制和资源管理。子类必须至少实现基本的 read 方法。
public abstract class InputStream implements Closeable {
public abstract int read() throws IOException;
public int read(byte[] b) throws IOException;
public int read(byte[] b, int off, int len) throws IOException;
public long skip(long n) throws IOException;
public int available() throws IOException;
public void close() throws IOException;
public synchronized void mark(int readlimit);
public synchronized void reset() throws IOException;
public boolean markSupported();
}
上面的代码展示了 InputStream 提供的关键方法。这些方法构成了 Java 中所有字节输入操作的基础。抽象的 read 方法必须由具体的子类实现。
读取单个字节
最基本的操作是从流中读取单个字节。read 方法将字节作为 int (0-255) 返回,或者在流的末尾返回 -1。此方法会阻塞,直到输入可用或到达流的末尾。
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
public class Main {
public static void main(String[] args) {
byte[] data = {65, 66, 67, 68, 69}; // ABCDE
try (InputStream is = new ByteArrayInputStream(data)) {
int byteRead;
while ((byteRead = is.read()) != -1) {
System.out.println("Read byte: " + byteRead +
" (" + (char) byteRead + ")");
}
System.out.println("End of stream reached");
} catch (IOException e) {
e.printStackTrace();
}
}
}
此示例演示了从 ByteArrayInputStream 读取字节。try-with-resources 确保正确关闭流。每个字节都以数值和字符的形式打印。循环会一直持续到 read 返回 -1,表示流的末尾。
将字节读入数组
为了获得更好的性能,一次性将多个字节读入字节数组。这减少了方法调用并提高了效率。read 方法返回实际读取的字节数,或者在流的末尾返回 -1。
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
public class Main {
public static void main(String[] args) {
String text = "Hello, InputStream!";
byte[] data = text.getBytes();
try (InputStream is = new ByteArrayInputStream(data)) {
byte[] buffer = new byte[10];
int bytesRead;
while ((bytesRead = is.read(buffer)) != -1) {
System.out.println("Read " + bytesRead + " bytes: " +
new String(buffer, 0, bytesRead));
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
此示例展示了批量读取到 10 字节的缓冲区中。String 构造函数仅将实际读取的字节转换为文本。循环会一直持续到 read 返回 -1。每次迭代最多处理 10 个字节。
跳过流中的字节
skip 方法允许跳过指定数量的字节。这比读取和丢弃数据更有效。实际跳过的字节数可能小于请求的数量。
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
public class Main {
public static void main(String[] args) {
byte[] data = new byte[100];
for (int i = 0; i < data.length; i++) {
data[i] = (byte) i;
}
try (InputStream is = new ByteArrayInputStream(data)) {
System.out.println("Available before skip: " + is.available());
long skipped = is.skip(50);
System.out.println("Skipped " + skipped + " bytes");
System.out.println("Next byte: " + is.read());
System.out.println("Available after skip: " + is.available());
} catch (IOException e) {
e.printStackTrace();
}
}
}
此示例创建了一个 100 字节的流,并跳过前 50 个字节。available 方法显示跳过之前和之后剩余的字节数。跳过后的读取显示跳过部分后的第一个字节 (50)。
Mark 和 Reset 功能
某些 InputStream 实现支持 mark/reset 操作。这允许在提前读取后返回到标记的位置。mark 方法指定在标记失效之前可以读取多少字节。
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
public class Main {
public static void main(String[] args) {
String text = "Markable InputStream Example";
try (InputStream is = new ByteArrayInputStream(text.getBytes())) {
if (is.markSupported()) {
System.out.println("Mark supported");
// Read and mark after 5 bytes
byte[] buffer = new byte[5];
is.read(buffer);
System.out.println("First 5 bytes: " + new String(buffer));
is.mark(10); // Mark with readlimit of 10 bytes
// Read next 5 bytes
is.read(buffer);
System.out.println("Next 5 bytes: " + new String(buffer));
// Reset to mark position
is.reset();
// Read again from mark
is.read(buffer);
System.out.println("After reset: " + new String(buffer));
} else {
System.out.println("Mark not supported");
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
此示例演示了 ByteArrayInputStream 的 mark/reset 功能。在读取 5 个字节后,我们标记该位置。读取超过 readlimit (10 字节) 会使标记失效。reset 返回到标记的位置。
从文件读取
FileInputStream 是一个常见的 InputStream 实现,用于读取文件。它直接从文件系统中的文件读取字节。始终关闭文件流以释放系统资源。
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
public class Main {
public static void main(String[] args) {
try (InputStream is = new FileInputStream("example.txt")) {
System.out.println("Available bytes: " + is.available());
byte[] buffer = new byte[1024];
int bytesRead;
StringBuilder content = new StringBuilder();
while ((bytesRead = is.read(buffer)) != -1) {
content.append(new String(buffer, 0, bytesRead));
}
System.out.println("File content:\n" + content.toString());
} catch (IOException e) {
e.printStackTrace();
}
}
}
此示例使用 FileInputStream 读取文件。available 方法给出初始文件大小。我们将数据块读入缓冲区并在 StringBuilder 中构建内容。try-with-resources 确保正确关闭文件句柄。
可用字节和流状态
available 方法估计可以读取而不会阻塞的字节数。对于文件,这通常意味着剩余字节。该方法对于检查流状态和进度很有用。
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
public class Main {
public static void main(String[] args) {
byte[] data = new byte[1000];
try (InputStream is = new ByteArrayInputStream(data)) {
System.out.println("Initial available: " + is.available());
byte[] buffer = new byte[100];
is.read(buffer);
System.out.println("After reading 100 bytes: " + is.available());
is.skip(300);
System.out.println("After skipping 300 bytes: " + is.available());
is.read(new byte[500]);
System.out.println("After reading 500 bytes: " + is.available());
} catch (IOException e) {
e.printStackTrace();
}
}
}
此示例在各种流操作期间跟踪可用字节。初始计数显示完整的流大小。每个读取或跳过操作都会减少可用计数。该方法有助于监控读取进度。
来源
在本文中,我们介绍了 Java InputStream 类的基本方法和特性。理解这些概念对于在 Java 应用程序中使用面向字节的输入操作至关重要。
作者
列出所有Java教程。