我听见有人猜
你是敌人潜伏的内线
和你相知多年
我确信对你的了解
你舍命救我画面
一一在眼前浮现
司空见惯了鲜血
你忘记你本是娇娆的红颜
感觉你我彼此都那么依恋
🎵 许嵩《内线》
在 Java 中,FileInputStream 是最常用的文件输入流类之一,用于从文件中读取字节数据。它是 Java I/O 流的一部分,允许程序以字节为单位读取文件内容,非常适合处理二进制文件(如图片、音频、视频等)以及文本文件的读取。本文将详细介绍 FileInputStream 的基本用法、内部实现及其适用场景。
1. 什么是 FileInputStream?
FileInputStream 是 Java 中 java.io 包的一部分,它继承自 InputStream 类。它主要用于从文件中读取数据,并且是以 字节流 的形式读取的,这意味着它处理的是原始的字节数据,而不是像 FileReader 那样处理字符数据。
FileInputStream 通常用于读取文件的原始内容,适合处理包括文本、图片、音频、视频等在内的各种文件类型。
FileInputStream 类的主要构造函数:
FileInputStream(String name):通过文件路径名称创建文件输入流。
FileInputStream(File file):通过文件对象创建文件输入流。
2. FileInputStream 的基本用法
FileInputStream 最基本的功能是从文件中逐字节读取数据。下面是一个简单的示例,展示如何使用 FileInputStream 读取文本文件。
示例 1:读取文件并输出内容
import java.io.FileInputStream;
import java.io.IOException;
public class FileInputStreamExample {
public static void main(String[] args) {
FileInputStream fis = null;
try {
// 创建 FileInputStream 对象,指定要读取的文件路径
fis = new FileInputStream("example.txt");
int content;
// 逐字节读取文件内容,直到文件结尾
while ((content = fis.read()) != -1) {
// 输出文件的内容(字符形式)
System.out.print((char) content);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
// 确保文件流被正确关闭
if (fis != null) {
fis.close();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
}
示例输出:
假设 example.txt 文件内容如下:
Hello, World!
程序将输出:
Hello, World!
在这个例子中,我们使用 FileInputStream 创建了一个文件输入流,并通过 read() 方法逐字节读取文件内容。当文件的末尾到达时,read() 方法返回 -1,表示读取结束。
3. FileInputStream 的方法
FileInputStream 继承自 InputStream 类,因此它具有一些基础的输入流方法。以下是 FileInputStream 的常用方法:
3.1 int read()
读取文件中的下一个字节,并返回该字节的值(0-255 范围内的整数)。如果到达文件末尾,返回 -1。
int content = fis.read();
3.2 int read(byte[] b)
一次性读取多个字节,并将其存储在指定的字节数组 b 中。返回实际读取的字节数,如果到达文件末尾则返回 -1。
byte[] buffer = new byte[1024];
int bytesRead = fis.read(buffer);
3.3 int available()
返回当前输入流中可以读取的字节数,但不一定准确。这个方法可以用来检查文件中是否还有字节可读。
int bytesAvailable = fis.available();
3.4 void close()
关闭文件输入流,释放与该流相关的所有系统资源。每次使用 FileInputStream 时,应当确保在使用完之后关闭流,以防资源泄漏。
fis.close();
4. 使用 read(byte[] b) 方法读取文件
除了单字节读取外,FileInputStream 还支持一次性读取多个字节,这种方式更高效,尤其是当文件较大时。通过将数据读取到字节数组中,可以减少对文件的多次访问。
示例 2:使用 read(byte[] b) 方法读取文件
import java.io.FileInputStream;
import java.io.IOException;
public class FileInputStreamBufferExample {
public static void main(String[] args) {
FileInputStream fis = null;
try {
fis = new FileInputStream("example.txt");
// 创建一个缓冲区,用于存储读取的数据
byte[] buffer = new byte[1024];
int bytesRead;
// 每次最多读取 buffer.length 字节
while ((bytesRead = fis.read(buffer)) != -1) {
// 将字节数组转化为字符串,并输出
String output = new String(buffer, 0, bytesRead);
System.out.print(output);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (fis != null) {
fis.close();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
}
在这个示例中,文件被读取到一个字节缓冲区中,每次最多读取 1024 字节。使用 byte[] 数组可以有效减少对磁盘的多次访问,提升性能,尤其是读取大文件时非常有用。
5. 文件不存在时的处理
当试图打开一个不存在的文件时,FileInputStream 会抛出 FileNotFoundException 异常。因此,应该在代码中捕获这个异常并处理。
示例 3:处理文件不存在的情况
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class FileNotFoundExample {
public static void main(String[] args) {
FileInputStream fis = null;
try {
// 尝试打开一个不存在的文件
fis = new FileInputStream("non_existent_file.txt");
} catch (FileNotFoundException e) {
System.out.println("文件未找到:" + e.getMessage());
} finally {
try {
if (fis != null) {
fis.close();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
}
在这种情况下,程序将输出类似如下的消息:
文件未找到:non_existent_file.txt (系统找不到指定的文件。)
6. 适用场景
FileInputStream 适用于读取任何类型的文件,尤其是需要读取 二进制文件(如图片、音频、视频等)时。以下是 FileInputStream 的一些典型应用场景:
读取文本文件:虽然 FileInputStream 可以处理文本文件,但通常建议使用 FileReader 或 BufferedReader 来处理字符数据。
读取二进制文件:处理图片、音频、视频等二进制文件是 FileInputStream 的主要用途。
流式读取大文件:通过 FileInputStream 逐步读取大文件的内容,避免一次性将整个文件加载到内存中,节省内存资源。
7. FileInputStream 的局限性
尽管 FileInputStream 在处理文件读取时非常有用,但它也有一些局限性:
7.1 低级 API
FileInputStream 是面向字节的低级 API,每次只能读取字节数据。对于处理字符数据(如文本文件),建议使用更高级的 API,如 BufferedReader 或 FileReader。
7.2 没有缓冲机制
FileInputStream 本身没有缓冲机制,意味着每次读取时都会直接访问底层文件系统。这在读取大文件或频繁的文件读取操作中性能不佳。为了提高读取效率,通常结合 BufferedInputStream 使用。
7.3 文件关闭
使用 FileInputStream 时必须手动关闭流,以释放资源。如果忘记关闭流,可能导致资源泄漏问题。在 Java 7 及以后的版本中,推荐使用 try-with-resources 语句来自动关闭流。
示例 4:使用 try-with-resources 自动关闭流
import java.io.FileInputStream;
import java.io.IOException;
public class TryWithResourcesExample {
public static void main(String[] args) {
// try-with-resources 语法,自动关闭文件输入流
try (FileInputStream fis = new FileInputStream("example.txt")) {
int content;
while ((content = fis.read()) != -1) {
System.out.print((char) content);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
使用 try-with-resources 可以确保流在使用完毕后自动关闭,即使发生异常,也无需显式调用 close() 方法。
8. 总结
FileInputStream 是 Java 中处理文件输入的基础工具,它通过字节流的方式读取文件内容,非常适合用于读取二进制文件。在使用 FileInputStream 时,开发者可以灵活选择是逐字节读取还是通过缓冲区批量读取数据。同时,在处理完文件输入后,务必要记得关闭流,以避免资源泄漏。
尽管 FileInputStream 是一个底层 I/O 工具,它在处理文件读取时仍然非常强大,但对于文本文件的处理来说,使用 BufferedReader 或其他高级 API 可能更加高效。
在日常开发中,FileInputStream 是文件读取的基础工具之一,理解它的工作方式和使用场景可以帮助开发者更好地处理 Java 中的文件操作。