FileInputStream 是 Java I/O (输入/输出) 库中一个非常核心的类,它属于 java.io 包,它的主要作用是从文件系统中的某个文件中读取原始字节流 (raw byte stream)。

你可以把它想象成一个连接你的 Java 程序和硬盘上文件的“水管”,数据(字节)就像水一样,通过这个水管从文件流向你的程序。
核心概念
- 字节流:
FileInputStream是一个字节输入流 (InputStream),这意味着它一次读取一个字节(8位),而不是像FileReader那样直接读取字符,这使得它非常适合处理所有类型的文件,包括:- 文本文件(如
.txt,.csv,.json) - 图片文件(如
.jpg,.png,.gif) - 音频/视频文件(如
.mp3,.mp4) - 可执行文件(
.exe) - 以及任何其他二进制文件。
- 文本文件(如
- 低级操作:
FileInputStream提供的是最底层的文件读取功能,它只负责“读”,不负责将字节解码成字符,在处理文本文件时,通常建议使用FileReader(它内部会使用字符集将字节解码为字符)或者更高级的Scanner、BufferedReader。
主要构造方法
创建 FileInputStream 对象通常有几种方式,最常用的是通过 File 对象或文件路径字符串。
1 构造方法
-
FileInputStream(String name)- 参数:
name是文件的路径字符串。 - 示例:
FileInputStream fis = new FileInputStream("C:\\data\\input.txt"); - 注意:如果文件不存在,会立即抛出
FileNotFoundException。
- 参数:
-
FileInputStream(File file)
(图片来源网络,侵删)- 参数:
file是一个java.io.File对象。 - 示例:
File file = new File("data/input.txt"); FileInputStream fis = new FileInputStream(file); - 注意:同样,如果文件不存在,会立即抛出
FileNotFoundException。
- 参数:
主要方法
FileInputStream 继承自 InputStream 类,并重写了其中的核心读取方法。
| 方法 | 描述 |
|---|---|
int read() |
读取一个字节的数据,并返回一个 0 到 255 之间的 int 值,如果到达文件末尾,则返回 -1。 |
int read(byte[] b) |
最多读取 b.length 个字节的数据到字节数组 b 中,返回实际读取的字节数,如果到达文件末尾,则返回 -1。这是最常用的方法。 |
int read(byte[] b, int off, int len) |
最多读取 len 个字节的数据到字节数组 b 中,从 off 位置开始存放,返回实际读取的字节数。 |
void close() |
关闭此文件输入流并释放与该流关联的所有系统资源。非常重要! |
long skip(long n) |
跳过输入流中的 n 个字节。 |
使用示例
下面通过几个例子来展示 FileInputStream 的具体用法。
示例 1:基本用法 - 逐字节读取
这个例子演示了如何使用 read() 方法一个字节一个字节地读取文件。注意:这种方法效率很低,不推荐用于大文件。
import java.io.FileInputStream;
import java.io.IOException;
public class FileInputStreamExample {
public static void main(String[] args) {
// 使用 try-with-resources 语句,可以自动关闭流,避免资源泄漏
try (FileInputStream fis = new FileInputStream("example.txt")) {
int byteData;
System.out.println("开始读取文件 (逐字节):");
// read() 方法返回一个字节,如果到达文件末尾,返回 -1
while ((byteData = fis.read()) != -1) {
// 将 int 类型的字节转换为 char 并打印
// 注意:这仅适用于单字节编码的文本文件,如 ASCII
System.out.print((char) byteData);
}
System.out.println("\n文件读取完毕。");
} catch (IOException e) {
System.err.println("发生错误: " + e.getMessage());
e.printStackTrace();
}
}
}
示例 2:高效用法 - 使用缓冲区(推荐)
这个例子使用 read(byte[] b) 方法,将数据读取到一个字节数组(缓冲区)中,这是处理文件的标准且高效的方式。

import java.io.FileInputStream;
import java.io.IOException;
public class FileInputStreamBufferedExample {
public static void main(String[] args) {
// 定义一个缓冲区,大小为 1024 字节
byte[] buffer = new byte[1024];
try (FileInputStream fis = new FileInputStream("example.txt")) {
int bytesRead;
System.out.println("开始读取文件 (使用缓冲区):");
// read(buffer) 会尝试将数据填满 buffer,并返回实际读取的字节数
while ((bytesRead = fis.read(buffer)) != -1) {
// 将读取到的字节转换为字符串并打印
// new String(buffer, 0, bytesRead) 只转换实际读取的部分
System.out.write(buffer, 0, bytesRead);
}
System.out.println("\n文件读取完毕。");
} catch (IOException e) {
System.err.println("发生错误: " + e.getMessage());
e.printStackTrace();
}
}
}
示例 3:处理二进制文件(如图片)
FileInputStream 的真正威力在于处理非文本文件,下面的例子演示了如何读取一个图片文件。
import java.io.FileInputStream;
import java.io.IOException;
public class ReadBinaryFileExample {
public static void main(String[] args) {
// 假设有一个名为 "image.jpg" 的文件
String filePath = "image.jpg";
try (FileInputStream fis = new FileInputStream(filePath)) {
byte[] imageBuffer = new byte[1024];
int totalBytesRead = 0;
int bytesRead;
System.out.println("开始读取二进制文件...");
while ((bytesRead = fis.read(imageBuffer)) != -1) {
totalBytesRead += bytesRead;
// 在实际应用中,这里会将读取到的字节数据写入另一个输出流
// 用于网络传输或复制文件
}
System.out.println("文件读取完成,总共读取了 " + totalBytesRead + " 个字节。");
} catch (IOException e) {
System.err.println("读取二进制文件时出错: " + e.getMessage());
}
}
}
最佳实践与重要注意事项
1 使用 try-with-resources (Java 7+)
这是最重要的一点。FileInputStream 是一个需要系统资源(文件句柄)的对象,如果在使用后没有正确关闭,可能会导致资源泄漏,使文件无法被其他程序访问,甚至耗尽系统资源。
try-with-resources 语句可以确保无论 try 块是否正常执行,流都会在语句结束时自动关闭。
// 推荐:自动关闭
try (FileInputStream fis = new FileInputStream("file.txt")) {
// ... 读取操作 ...
} catch (IOException e) {
// ... 处理异常 ...
}
// 不推荐:需要手动关闭,容易出错
FileInputStream fis = null;
try {
fis = new FileInputStream("file.txt");
// ... 读取操作 ...
} catch (IOException e) {
// ... 处理异常 ...
} finally {
if (fis != null) {
try {
fis.close(); // 必须在 finally 块中关闭
} catch (IOException e) {
e.printStackTrace();
}
}
}
2 异常处理
FileInputStream 的构造方法和 read() 方法都可能抛出 IOException(及其子类 FileNotFoundException),你必须使用 try-catch 块来捕获这些异常,或者使用 throws 关键字将异常声明抛给上层调用者处理。
3 FileInputStream vs. FileReader
| 特性 | FileInputStream |
FileReader |
|---|---|---|
| 数据类型 | 字节流 | 字符流 |
| 读取单位 | 字节 | 字符 |
| 适用场景 | 所有文件(二进制、文本) | 仅文本文件 |
| 编码处理 | 无,直接读取原始字节 | 有,可以指定字符集(如 UTF-8)将字节解码为字符 |
| 继承关系 | InputStream |
Reader |
- 如果要处理图片、音频、视频或任何非文本文件,
