FileWriter 无法可靠指定编码导出 CSV,应改用 OutputStreamWriter+FileOutputStream 或 Files.write 并显式指定 UTF-8 编码,且需写入 BOM(\uFEFF)以确保 Excel 正确识别。

FileWriter 本身不能可靠指定编码格式导出 CSV——它没有接受 Charset 参数的构造方法(JDK 11+ 虽新增了 FileWriter(String, Charset),但兼容性差、行为不一致,且 CSV 场景下极易踩坑)。真正安全的做法是绕过 FileWriter,改用底层可控的流组合或 NIO 工具。
为什么 FileWriter(String) 写 CSV 必然乱码
Windows 系统默认编码是 GBK,而现代 CSV 文件(尤其含中文)必须用 UTF-8;FileWriter 构造时若只传路径字符串,就强制走系统默认编码。即使源码保存为 UTF-8,写入后文件字节序列仍是 GBK 编码,Excel 打开时显示为“浣犲ソ”这类乱码。
- 不是文件内容错了,是字节和解码方式错配
-
-Dfile.encoding=UTF-8全局参数对第三方工具(如 Excel)无效 - CSV 不是纯文本协议,Excel 默认按 ANSI(即系统默认编码)解析无 BOM 的 UTF-8 文件
正确写法:用 OutputStreamWriter + FileOutputStream 指定 UTF-8
这是最通用、JDK 6+ 全版本兼容的方案,明确控制编码,且可轻松添加 BOM(让 Excel 正确识别 UTF-8)。
从 CSV 数据集生成图数据库加载器和三元组映射。将表格 CSV 数据转换为图数据库可直接使用的节点、边和三元组。
- 写入前先输出 BOM:
bw.write("\uFEFF");(UTF-8 BOM 是EF BB BF,对应 Unicode 字符\uFEFF) - 必须用
OutputStreamWriter构造函数第二个参数传"UTF-8",不能依赖系统属性 - 套一层
BufferedWriter提升小数据写入性能(CSV 行多、单行短,缓冲很关键)
try (FileOutputStream fos = new FileOutputStream("data.csv");
OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF-8");
BufferedWriter bw = new BufferedWriter(osw)) {
bw.write("\uFEFF"); // 写入 BOM
bw.write("姓名,年龄,城市");
bw.newLine();
bw.write("张三,25,北京");
bw.newLine();
} catch (IOException e) {
e.printStackTrace();
}
更推荐:用 Files.write 写 CSV(Java 7+)
代码更短、自动关流、天然支持 StandardCharsets.UTF_8,适合简单 CSV(无复杂转义)。
- 注意:
Files.write默认覆盖,追加需显式加StandardOpenOption.APPEND - 若要带 BOM,仍需手动 prepend
"\uFEFF"到第一行内容中 - 每行必须自己拼好(含逗号、引号转义),它不处理 CSV 格式逻辑
List<String> lines = Arrays.asList(
"\uFEFF姓名,年龄,城市",
"李四,30,上海",
"王五,28,广州"
);
Files.write(Paths.get("data.csv"), lines, StandardCharsets.UTF_8);
容易被忽略的关键点
CSV 乱码问题从来不只是“写对编码”,还卡在读取端:
- Excel 打开无 BOM 的 UTF-8 CSV 时,会当成 ANSI 解析——加
\uFEFF是最简单有效的兼容手段 - 如果 CSV 含英文逗号、换行或双引号,
Files.write和裸BufferedWriter都不会自动转义,必须自己处理(比如用 OpenCSV 或 Apache Commons CSV 库) - IDE 中 Java 源文件编码、终端默认编码、JVM 启动参数三者不一致时,
System.out.println输出可能误导你判断“写对了”

















