ZetCode

Java FileOutputStream 类

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

java.io.FileOutputStream 类是一个用于将数据写入文件的输出流。它将原始字节写入文件,并且是 Java I/O 包的一部分。FileOutputStream 用于将字节流写入文件或文件描述符。

为了获得更好的性能,FileOutputStream 通常被封装在更高级的 writer 中,例如 BufferedOutputStreamPrintStream。它支持追加和覆盖模式进行文件写入。这个类对于并发访问不是线程安全的。

FileOutputStream 类概述

FileOutputStream 扩展了 OutputStream 并提供了基本的文件写入功能。主要方法包括用于字节和字节数组的写入操作。该类自动处理文件的创建和打开。

public class FileOutputStream extends OutputStream {
    public FileOutputStream(String name) throws FileNotFoundException;
    public FileOutputStream(String name, boolean append) throws FileNotFoundException;
    public FileOutputStream(File file) throws FileNotFoundException;
    public FileOutputStream(File file, boolean append) throws FileNotFoundException;
    public FileOutputStream(FileDescriptor fdObj);
    public void write(int b) throws IOException;
    public void write(byte[] b) throws IOException;
    public void write(byte[] b, int off, int len) throws IOException;
    public void close() throws IOException;
    public FileChannel getChannel();
    public final FileDescriptor getFD() throws IOException;
}

上面的代码展示了 FileOutputStream 提供的关键方法。这些方法允许以各种方式将字节写入文件。该类还提供对底层文件通道和描述符的访问。

创建 FileOutputStream

可以使用文件路径字符串、File 对象或文件描述符创建 FileOutputStream。append 参数确定是覆盖还是追加到现有文件。如果无法打开文件,所有构造函数都会抛出 FileNotFoundException。

Main.java
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

public class Main {

    public static void main(String[] args) {
        try {
            // Create with file path (overwrite mode)
            FileOutputStream fos1 = new FileOutputStream("output1.txt");
            
            // Create with File object (append mode)
            File file = new File("output2.txt");
            FileOutputStream fos2 = new FileOutputStream(file, true);
            
            System.out.println("FileOutputStream created (overwrite mode)");
            System.out.println("FileOutputStream created (append mode)");
            
            fos1.close();
            fos2.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

此示例演示了创建 FileOutputStream 的不同方法。第一个使用文件路径,并默认为覆盖模式。第二个使用 File 对象,并启用追加模式。完成后始终关闭流以释放资源。

写入单个字节

最简单的写入操作是将单个字节写入文件。该字节被指定为一个 int,只写入最低 8 位。此方法对于批量数据效率不高,但对于特定情况很有用。

Main.java
import java.io.FileOutputStream;
import java.io.IOException;

public class Main {

    public static void main(String[] args) {
        try (FileOutputStream fos = new FileOutputStream("bytes.txt")) {
            
            // Write ASCII characters A-Z
            for (int i = 65; i <= 90; i++) {
                fos.write(i);
            }
            
            System.out.println("Bytes written successfully");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

此示例将 ASCII 字符 A-Z 写入文件。每个字符都作为单个字节写入。try-with-resources 语句确保正确关闭流。请注意,此方法不适用于 ASCII 范围之外的 Unicode 字符。

写入字节数组

为了获得更好的性能,请使用字节数组一次写入多个字节。这减少了本机 I/O 操作。可以写入整个数组或一部分。这是写入批量数据的最有效方式。

Main.java
import java.io.FileOutputStream;
import java.io.IOException;

public class Main {

    public static void main(String[] args) {
        try (FileOutputStream fos = new FileOutputStream("data.bin")) {
            
            // Create sample data
            byte[] data = new byte[256];
            for (int i = 0; i < 256; i++) {
                data[i] = (byte) i;
            }
            
            // Write entire array
            fos.write(data);
            
            // Write portion of array
            fos.write(data, 0, 128);
            
            System.out.println("Byte arrays written successfully");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

此示例演示了将字节数组写入文件。首先,创建一个 256 字节的数组,并用值 0-255 填充。写入整个数组,然后只写入前 128 个字节。这种方法比写入单个字节快得多。

追加到文件

FileOutputStream 可以追加到现有文件,而不是覆盖它们。这由构造函数中的 append 参数控制。追加对于日志文件或累积数据时很有用。

Main.java
import java.io.FileOutputStream;
import java.io.IOException;

public class Main {

    public static void main(String[] args) {
        String message = "Appended line\n";
        
        try (FileOutputStream fos = 
                new FileOutputStream("log.txt", true)) {
            
            // Append multiple messages
            for (int i = 1; i <= 5; i++) {
                String entry = i + ": " + message;
                fos.write(entry.getBytes());
            }
            
            System.out.println("Messages appended to file");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

此示例演示了如何将数据追加到现有文件。FileOutputStream 是以启用追加模式创建的。五个日志条目被写入文件。每个写入操作都会添加到文件末尾,而不是覆盖它。

使用 FileChannel

FileOutputStream 提供对底层 FileChannel 的访问。这允许进行高级文件操作,例如文件锁定或内存映射 I/O。通道保持打开状态,直到流关闭。

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

public class Main {

    public static void main(String[] args) {
        try (FileOutputStream fos = new FileOutputStream("channel.txt");
             FileChannel channel = fos.getChannel()) {
            
            String text = "Written using FileChannel";
            ByteBuffer buffer = ByteBuffer.wrap(text.getBytes());
            
            // Write through channel
            channel.write(buffer);
            
            System.out.println("Data written via FileChannel");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

此示例演示了如何从 FileOutputStream 使用 FileChannel。创建一个 ByteBuffer 并填充数据。通道将缓冲区内容写入文件。与基本的写入方法相比,这种方法提供了对文件操作的更多控制。

错误处理和清理

在使用文件流时,正确的错误处理至关重要。即使发生异常,也必须关闭资源。Try-with-resources 确保正确清理。文件操作应处理潜在的安全性和权限问题。

Main.java
import java.io.FileOutputStream;
import java.io.IOException;

public class Main {

    public static void main(String[] args) {
        try (FileOutputStream fos = new FileOutputStream("important.dat")) {
            
            // Critical data writing
            byte[] criticalData = getCriticalData();
            fos.write(criticalData);
            
            // Force write to disk
            fos.getFD().sync();
            
            System.out.println("Critical data saved successfully");
        } catch (IOException e) {
            System.err.println("Failed to write critical data: " + e.getMessage());
            // Handle error appropriately
        }
    }
    
    private static byte[] getCriticalData() {
        // Simulate getting important data
        return "Very important information".getBytes();
    }
}

此示例显示了文件操作的健壮错误处理。try-with-resources 确保流已关闭。文件描述符的 sync 方法强制将数据写入磁盘。错误被捕获并得到适当处理。建议在生产代码中使用此模式。

来源

Java FileOutputStream 类文档

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

作者

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

列出所有Java教程