理解 FileInputStream 的定位与适用场景
掌握三种构造方式及核心读取方法
能够正确读取二进制文件(如图片、音频)
了解 available()、skip() 等辅助方法的作用
学会安全地管理文件流资源
FileInputStream 是 Java 中用于从文件读取原始字节数据的输入流,继承自 InputStream。它是处理二进制文件(如图片、音频、视频、压缩包)的标准工具。
重要提示:虽然可以用它读取文本文件,但不推荐!应使用
FileReader或InputStreamReader(可指定编码),避免乱码问题。
核心特性
字节级操作:每次读取 1 个或多个 byte(8 位)
无缓冲:直接从磁盘读取,频繁小量读取性能较差
平台无关:自动适配不同操作系统的文件系统
支持 NIO:可通过 getChannel() 获取 FileChannel 进行高效 I/O
public class FileInputStream extends InputStream继承 InputStream:获得 read()、close() 等基础方法
实现底层文件读取:将操作系统文件句柄封装为 Java 流
FileInputStream 提供三种构造方式:
// 方式1:直接传路径
FileInputStream fis1 = new FileInputStream("config.properties");
// 方式2:先有 File 对象
File file = new File("logs/app.log");
FileInputStream fis2 = new FileInputStream(file);
// 方式3:从标准输入(极少使用)
FileInputStream fis3 = new FileInputStream(FileDescriptor.in);推荐:优先使用
String或File构造器,清晰且安全
逐字节读取文件
以下程序演示如何读取文本文件(仅作演示,实际应使用字符流):
import java.io.*;
public class FileInputStreamExample {
public static void main(String[] args) {
// 确保 file1.txt 存在,内容如:
// Hello Java FileInputStream!
try (FileInputStream fis = new FileInputStream("file1.txt")) {
System.out.println("文件通道: " + fis.getChannel());
System.out.println("文件描述符: " + fis.getFD());
System.out.println("预估剩余字节数: " + fis.available());
// 跳过前4个字节("Hell")
fis.skip(4);
System.out.println("\n文件内容(跳过4字节后):");
int byteData;
while ((byteData = fis.read()) != -1) {
// 将 byte 转为 char 输出(仅适用于ASCII文本!)
System.out.print((char) byteData);
}
} catch (FileNotFoundException e) {
System.err.println("文件未找到: " + e.getMessage());
} catch (IOException e) {
System.err.println("读取错误: " + e.getMessage());
}
}
}假设 file1.txt 内容为:
Hello Java FileInputStream!输出:
文件通道: sun.nio.ch.FileChannelImpl@...
文件描述符: java.io.FileDescriptor@...
预估剩余字节数: 26
文件内容(跳过4字节后):
o Java FileInputStream!注意:
(char)byteData仅对 ASCII 文本有效!非 ASCII 字符(如中文)会乱码
FileInputStream 的真正价值在于处理二进制数据。以下程序复制一张图片:
import java.io.*;
public class ImageCopy {
public static void main(String[] args) {
try (FileInputStream fis = new FileInputStream("source.jpg");
FileOutputStream fos = new FileOutputStream("copy.jpg")) {
byte[] buffer = new byte[1024]; // 1KB 缓冲区
int bytesRead;
while ((bytesRead = fis.read(buffer)) != -1) {
fos.write(buffer, 0, bytesRead); // 写入实际读取的字节数
}
System.out.println("图片复制完成!");
} catch (IOException e) {
System.err.println("文件操作失败: " + e.getMessage());
}
}
}使用缓冲区(
byte[])大幅提升性能,避免逐字节 I/O
用途明确:仅用于二进制文件读取;文本文件用 FileReader/InputStreamReader
必须关闭:使用 try-with-resources 自动释放资源
避免逐字节读:使用 byte[] 缓冲区或 BufferedInputStream
不要依赖 available():以 read() == -1 判断结束
大文件处理:考虑 FileChannel + 内存映射提升性能
异常处理:捕获 FileNotFoundException 和 IOException
FileInputStream 是读取原始字节的标准方式,适用于二进制文件
三种构造器:String、File、FileDescriptor
核心方法:read()(单字节 / 数组)、skip()、available()(估算)
无内置缓冲,性能敏感场景需包装 BufferedInputStream
通过 getChannel() 支持 NIO 高级功能
永远不要用它直接读取非 ASCII 文本(会乱码!)
为什么用 FileInputStream 读取包含中文的文本文件会出现乱码?如何正确读取?
fis.read(buffer) 返回值的意义是什么?为什么不能假设它总是等于 buffer.length?
在什么场景下应该直接使用 FileInputStream,什么场景下应包装 BufferedInputStream?性能差异有多大?