杰瑞科技汇

Java FileWriter 写文件,如何正确使用与避坑?

FileWriter 是什么?

FileWriter 是 Java I/O 库中的一个类,它属于 java.io 包,它的主要作用是将字符数据写入文件,你可以把它想象成一个“字符写入器”,它专门处理文本(如 .txt, .java, .xml 等文件),而不是二进制数据(如图片、视频)。

Java FileWriter 写文件,如何正确使用与避坑?-图1
(图片来源网络,侵删)

FileWriter 的工作原理是:它将写入的字符(char)转换为底层的字节(byte)流,并使用平台的默认字符编码(通常是 UTF-8)进行编码。


基本用法:写入一个新文件

这是最简单的用法,它会创建一个新文件(如果文件不存在)或覆盖一个已存在的文件。

核心步骤:

  1. 创建 FileWriter 对象:指定要写入的文件路径。
  2. 写入数据:使用 write() 方法。
  3. 关闭流非常重要! 使用 close() 方法关闭 FileWriter,以确保所有数据都被刷新到文件中,并释放系统资源。

代码示例:

import java.io.FileWriter;
import java.io.IOException;
public class FileWriterExample {
    public static void main(String[] args) {
        // 定义要写入的文件路径
        String filePath = "my-new-file.txt";
        // 使用 try-with-resources 语句(推荐)
        // 它会自动在 try 块执行完毕后关闭资源,即使发生异常
        try (FileWriter writer = new FileWriter(filePath)) {
            // 写入一个字符串
            writer.write("Hello, FileWriter!\n");
            // 写入另一个字符串
            writer.write("This is the second line of text.");
            System.out.println("文件写入成功!");
        } catch (IOException e) {
            // 如果发生 I/O 错误(如没有写入权限),会捕获这个异常
            System.err.println("写入文件时发生错误: " + e.getMessage());
            e.printStackTrace();
        }
        // writer 会自动被关闭,无需手动调用 writer.close()
    }
}

运行结果: 程序执行后,会在项目根目录下创建一个名为 my-new-file.txt 的文件,内容如下:

Hello, FileWriter!
This is the second line of text.

FileWriter 的关键构造函数

FileWriter 提供了几个构造函数,以满足不同的需求:

Java FileWriter 写文件,如何正确使用与避坑?-图2
(图片来源网络,侵删)
构造函数 描述
FileWriter(String fileName) 创建一个 FileWriter 对象,与名为 fileName 的文件关联,如果文件已存在,则其内容将被覆盖。
FileWriter(File file) 创建一个 FileWriter 对象,与 File 对象关联,如果文件已存在,则其内容将被覆盖。
FileWriter(String fileName, boolean append) 创建一个 FileWriter 对象。append 参数为 true 时,数据会被追加到文件末尾,而不是覆盖。
FileWriter(File file, boolean append) 同上,但使用 File 对象作为文件路径。

追加模式 vs. 覆盖模式

这是 FileWriter 一个非常重要的特性。

覆盖模式(默认)

如果你只想保留最新的内容,使用默认构造函数或设置 appendfalse

// 这会先清空文件,然后写入 "New content"
try (FileWriter writer = new FileWriter("my-new-file.txt")) {
    writer.write("New content");
}

追加模式

如果你想在文件现有内容的末尾添加新内容,必须使用带 append 参数的构造函数,并将 append 设为 true

// 这会在 "my-new-file.txt" 文件末尾追加 "Appended content"
try (FileWriter writer = new FileWriter("my-new-file.txt", true)) {
    writer.write("\nAppended content"); // 添加一个换行符,让新内容从新的一行开始
}

示例: 假设 my-new-file.txt 原有内容是 Hello, FileWriter!

Java FileWriter 写文件,如何正确使用与避坑?-图3
(图片来源网络,侵删)
// 第一次写入(覆盖)
try (FileWriter writer1 = new FileWriter("my-new-file.txt")) {
    writer1.write("This is the first line.");
}
// 第二次写入(追加)
try (FileWriter writer2 = new FileWriter("my-new-file.txt", true)) {
    writer2.write("\nThis is the second line.");
}

将是:

This is the first line.
This is the second line.

重要:资源管理与 try-with-resources

在第一个例子中,我们使用了 try-with-resources 语法,这是现代 Java (7+) 推荐的最佳实践。

为什么必须关闭 FileWriter 当你写入数据时,数据可能首先被存储在内存缓冲区中,而不是立即写入硬盘。close() 方法会执行一个“刷新”(flush)操作,将缓冲区中剩余的所有数据强制写入文件,然后关闭文件流,释放文件句柄等系统资源。

如果不关闭文件,可能会导致:

  1. 数据丢失:程序异常终止时,缓冲区中的数据可能没有写入文件。
  2. 资源泄漏:系统无法回收文件句柄,如果长时间运行,可能会耗尽系统资源。

try-with-resources 的优点: 它会自动调用 close() 方法,无论 try �块是正常结束还是抛出异常,这极大地简化了代码,并避免了资源泄漏的风险。

不推荐的旧写法(手动关闭):

FileWriter writer = null;
try {
    writer = new FileWriter("my-file.txt");
    writer.write("some text");
} catch (IOException e) {
    e.printStackTrace();
} finally {
    // 必须在 finally 块中关闭,以确保即使发生异常也能执行
    if (writer != null) {
        try {
            writer.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

可以看到,手动关闭非常繁琐且容易出错。


进阶用法:写入字符数组和追加换行符

FileWriter 还提供了其他有用的写入方法。

写入字符数组

char[] charArray = "这是一个字符数组".toCharArray();
try (FileWriter writer = new FileWriter("char-array.txt")) {
    writer.write(charArray);
}

追加换行符

在不同操作系统上,换行符可能不同(Windows 是 \r\n,Linux/macOS 是 \n),为了更好的跨平台兼容性,可以使用 System.lineSeparator()

try (FileWriter writer = new FileWriter("lines.txt")) {
    writer.write("第一行" + System.lineSeparator());
    writer.write("第二行" + System.lineSeparator());
    writer.write("第三行");
}

FileWriter 的局限性

FileWriter 虽然简单,但也有其局限性:

  1. 性能问题:每次调用 write() 方法都可能直接触发 I/O 操作,效率较低,对于大量数据写入,通常会结合 BufferedWriter 来使用,它会在内存中创建一个缓冲区,减少实际的 I/O 次数,从而大幅提升性能。
  2. 编码问题FileWriter 使用的是 JVM 默认的字符编码,这在不同环境下可能会导致乱码,如果你的系统默认编码是 GBK,但你想写入 UTF-8 编码的文件,就会出现问题。

如何解决编码问题?

可以使用 OutputStreamWriter 来包装 FileOutputStream,并明确指定字符编码。

import java.io.*;
import java.nio.charset.StandardCharsets; // 推荐使用 StandardCharsets 枚举
public class FileWriterWithEncoding {
    public static void main(String[] args) {
        String filePath = "encoded-file.txt";
        String text = "你好,世界!Hello, World!";
        // 使用 try-with-resources 确保 OutputStreamWriter 和 FileOutputStream 都被关闭
        try (FileOutputStream fos = new FileOutputStream(filePath);
             OutputStreamWriter osw = new OutputStreamWriter(fos, StandardCharsets.UTF_8);
             FileWriter writer = new FileWriter(osw)) { // 注意:这里 FileWriter 是多余的,直接用 OutputStreamWriter 即可
            // 正确的写法是直接使用 OutputStreamWriter
            // osw.write(text);
            System.out.println("文件以 UTF-8 编码写入成功!");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

更简洁的写法(直接使用 OutputStreamWriter):

// 正确且推荐的做法
try (OutputStreamWriter osw = new OutputStreamWriter(
        new FileOutputStream("encoded-file.txt"), StandardCharsets.UTF_8)) {
    osw.write("你好,世界!Hello, World!");
    System.out.println("文件以 UTF-8 编码写入成功!");
} catch (IOException e) {
    e.printStackTrace();
}

如何提升性能

分享:
扫描分享到社交APP
上一篇
下一篇