ZetCode

Java FileInputStream 类

最后修改时间:2025 年 4 月 16 日

java.io.FileInputStream 类用于在 Java 中从文件读取原始字节。它是 Java 的 I/O 包的一部分,非常适合读取二进制文件,如图像或可执行文件。FileInputStream 扩展了 InputStream。

FileInputStream 提供低级文件访问操作。它逐字节或以块为单位读取数据。如果文件不存在,该类会抛出 FileNotFoundException 异常。它没有缓冲,因此为了获得更好的性能,请将其包装在 BufferedInputStream 中。

FileInputStream 类概述

FileInputStream 提供了几个构造函数,用于从文件创建输入流。关键方法包括读取操作、流跳过和可用字节检查。该类默认不支持 mark/reset 操作。

public class FileInputStream extends InputStream {
    public FileInputStream(String name) throws FileNotFoundException;
    public FileInputStream(File file) throws FileNotFoundException;
    public FileInputStream(FileDescriptor fdObj);
    public 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 FileChannel getChannel();
    public final FileDescriptor getFD() throws IOException;
}

上面的代码展示了 FileInputStream 提供的关键方法。这些方法允许在字节级别从文件读取数据。该类还提供了对底层文件描述符和通道的访问,以便进行高级操作。

创建 FileInputStream

FileInputStream 可以使用文件路径字符串、File 对象或文件描述符来创建。使用后务必关闭流以释放系统资源。try-with-resources 语句确保了正确的流关闭。

Main.java
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

public class Main {

    public static void main(String[] args) {
        // Using file path string
        try (FileInputStream fis1 = new FileInputStream("data.txt")) {
            System.out.println("Stream created from path");
        } catch (FileNotFoundException e) {
            System.out.println("File not found");
        } catch (IOException e) {
            e.printStackTrace();
        }

        // Using File object
        File file = new File("data.txt");
        try (FileInputStream fis2 = new FileInputStream(file)) {
            System.out.println("Stream created from File object");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

此示例演示了创建 FileInputStream 的不同方法。第一个使用文件路径字符串,第二个使用 File 对象。两个流都由 try-with-resources 自动关闭。如果文件不存在或无法打开,则会抛出 FileNotFoundException 异常。

从文件读取单个字节

读取数据的最简单方法是使用 read 方法逐字节读取。它返回下一个数据字节,如果到达文件末尾则返回 -1。这种方法对于大文件效率不高,但对于小文件来说很简单。

Main.java
import java.io.FileInputStream;
import java.io.IOException;

public class Main {

    public static void main(String[] args) {
        try (FileInputStream fis = new FileInputStream("data.txt")) {
            int byteData;
            System.out.println("Reading file byte by byte:");
            
            while ((byteData = fis.read()) != -1) {
                System.out.print((char) byteData);
            }
            
            System.out.println("\nFile reading complete");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

此示例逐字节读取文本文件并打印每个字符。read 方法返回一个表示字节值的 int。我们将其转换为 char 以进行文本显示。循环继续,直到 read 返回 -1(文件末尾)。这种方法适用于文本文件和二进制文件。

将字节读入字节数组

为了获得更好的性能,一次将多个字节读入一个字节数组。这减少了 I/O 操作的数量。read 方法返回实际读取的字节数,可能小于数组的长度。

Main.java
import java.io.FileInputStream;
import java.io.IOException;

public class Main {

    public static void main(String[] args) {
        try (FileInputStream fis = new FileInputStream("largefile.dat")) {
            byte[] buffer = new byte[1024]; // 1KB buffer
            int bytesRead;
            
            System.out.println("Reading file in chunks:");
            
            while ((bytesRead = fis.read(buffer)) != -1) {
                System.out.println("Read " + bytesRead + " bytes");
                // Process the buffer here
            }
            
            System.out.println("File reading complete");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

此示例演示了使用字节数组缓冲区以块为单位读取文件。缓冲区大小(1024 字节)可以根据性能进行调整。read 方法填充缓冲区并返回读取的字节数。在文件末尾,它返回 -1。这种方法比逐字节读取快得多。

读取文件的特定部分

FileInputStream 允许通过指定偏移量和长度参数来读取文件的特定部分。当您只需要处理文件的某些部分时,这非常有用。read 方法确保了线程安全的操作。

Main.java
import java.io.FileInputStream;
import java.io.IOException;

public class Main {

    public static void main(String[] args) {
        try (FileInputStream fis = new FileInputStream("data.bin")) {
            byte[] buffer = new byte[100];
            
            // Read 50 bytes starting from position 10
            fis.skip(10);
            int bytesRead = fis.read(buffer, 0, 50);
            
            System.out.println("Read " + bytesRead + " bytes from position 10");
            System.out.println("First byte: " + buffer[0]);
            System.out.println("Last byte: " + buffer[bytesRead-1]);
            
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

此示例显示了如何读取文件的特定部分。我们首先跳过 10 个字节,然后将 50 个字节读入缓冲区。read 方法的参数指定在缓冲区中存储数据的位置。这种方法对于处理具有已知格式的结构化二进制文件很有用。

获取可用字节并跳过数据

available 方法返回可以读取而不会阻塞的字节的估计值。skip 方法允许跳过流中的字节。这两种方法都适用于浏览文件。

Main.java
import java.io.FileInputStream;
import java.io.IOException;

public class Main {

    public static void main(String[] args) {
        try (FileInputStream fis = new FileInputStream("data.txt")) {
            System.out.println("Total available bytes: " + fis.available());
            
            // Skip first 10 bytes
            long skipped = fis.skip(10);
            System.out.println("Skipped " + skipped + " bytes");
            
            // Read next byte
            int nextByte = fis.read();
            System.out.println("Next byte: " + (char) nextByte);
            
            System.out.println("Remaining bytes: " + fis.available());
            
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

此示例演示了使用 available 和 skip 方法。Available 显示可以立即读取多少字节。Skip 在不读取数据的情况下移动文件指针。这些方法在处理具有标头或元数据部分的二进制文件格式时特别有用。

将 FileInputStream 与 FileChannel 一起使用

FileInputStream 提供了对底层 FileChannel 的访问,以便进行高级文件操作。通道支持内存映射 I/O 和文件锁定等功能,这些功能单独通过流接口无法使用。

Main.java
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

public class Main {

    public static void main(String[] args) {
        try (FileInputStream fis = new FileInputStream("data.bin");
             FileChannel channel = fis.getChannel()) {
            
            ByteBuffer buffer = ByteBuffer.allocate(1024);
            
            while (channel.read(buffer) > 0) {
                buffer.flip(); // Prepare buffer for reading
                
                while (buffer.hasRemaining()) {
                    System.out.print((char) buffer.get());
                }
                
                buffer.clear(); // Prepare buffer for next read
            }
            
            System.out.println("\nFile reading complete via channel");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

此示例显示了如何使用 FileInputStream 的通道进行更高级的 I/O 操作。我们创建一个 ByteBuffer 并通过通道读取数据。通道为大文件提供了更好的性能,并支持其他功能,如文件锁定。这结合了流和通道 I/O 方法。

来源

Java FileInputStream 类文档

在本文中,我们介绍了 Java FileInputStream 类的基本方法和特性。理解这些概念对于在 Java 应用程序中使用文件 I/O 操作至关重要。

作者

我叫 Jan Bodnar,是一名经验丰富的程序员,在这个领域拥有多年的经验。我从 2007 年开始撰写编程文章,至今已撰写了 1,400 多篇文章和 8 本电子书。凭借超过八年的教学经验,我致力于分享我的知识并帮助其他人掌握编程概念。

列出所有Java教程