27

我有一个 Java 存储过程,它使用Resultset对象从表中获取记录并创建一个 CS Vfile。

BLOB retBLOB = BLOB.createTemporary(conn, true, BLOB.DURATION_SESSION);
retBLOB.open(BLOB.MODE_READWRITE);
OutputStream bOut = retBLOB.setBinaryStream(0L);

ZipOutputStream zipOut = new ZipOutputStream(bOut);
PrintStream out = new PrintStream(zipOut,false,"UTF-8");
out.write('\ufeff');
out.flush();

zipOut.putNextEntry(new ZipEntry("filename.csv"));
while (rs.next()){
    out.print("\"" + rs.getString(i) + "\"");
    out.print(",");
}
out.flush();

zipOut.closeEntry();
zipOut.close();
retBLOB.close();

return retBLOB;

但是生成的 CSV 文件没有显示正确的德语字符。Oracle 数据库也有一个NLS_CHARACTERSET值 UTF8。

请建议。

4

8 回答 8

77
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(...), StandardCharsets.UTF_8));
out.write('\ufeff');
out.write(...);

这会正确地将 0xEF 0xBB 0xBF 写入文件,这是 BOM 的 UTF-8 表示。

于 2011-11-14T11:18:48.947 回答
16

以防万一人们使用s PrintStream,你需要做一些不同的事情。虽然 aWriter可以将单个字节转换为 3 个字节,但 aPrintStream需要单独使用 UTF-8 BOM 的所有 3 个字节:

    // Print utf-8 BOM
    PrintStream out = System.out;
    out.write('\ufeef'); // emits 0xef
    out.write('\ufebb'); // emits 0xbb
    out.write('\ufebf'); // emits 0xbf

或者,您可以直接使用十六进制值:

    PrintStream out = System.out;
    out.write(0xef); // emits 0xef
    out.write(0xbb); // emits 0xbb
    out.write(0xbf); // emits 0xbf
于 2016-03-30T14:29:54.940 回答
11

要在 UTF-8 中编写 BOM,您需要PrintStream.print(),而不是PrintStream.write().

此外,如果您想在csv文件中包含 BOM,我想您需要在putNextEntry().

于 2010-12-08T15:41:35.367 回答
11

PrintStream#print

我认为out.write('\ufeff');实际上应该是out.print('\ufeff');,调用该java.io.PrintStream#print方法。

根据javadoc,该write(int)方法实际上写入一个字节......没有任何字符编码。所以out.write('\ufeff');写入字节0xff。相比之下,该print(char)方法使用流的编码将字符编码为一个或字节,然后写入这些字节。

Unicode 9 规范的第 23.8 节所述,UTF-8 的 BOM 是EF BB BF. 该序列是您在'\ufeff'. 请参阅:为什么 UTF-8 BOM 字节 efbbbf 可以替换为 \ufeff?.

于 2010-12-08T15:42:06.907 回答
5

您将其添加为第一个 CSV 字符串

String CSV = "";
byte[] BOM = {(byte) 0xEF,(byte) 0xBB,(byte) 0xBF};
CSV = new String(BOM) + CSV;

这为我工作。

于 2020-07-15T15:48:45.220 回答
0

就我而言,它适用于代码:

PrintWriter out = new PrintWriter(new File(filePath), "UTF-8");
out.write(csvContent);
out.flush();
out.close();
于 2013-12-19T09:01:34.900 回答
0

如果您只想修改同一个文件(没有新文件并删除旧文件,因为我遇到了问题)

private void addBOM(File fileInput) throws IOException {
    try (RandomAccessFile file = new RandomAccessFile(fileInput, "rws")) {
        byte[] text = new byte[(int) file.length()];
        file.readFully(text);
        file.seek(0);
        byte[] bom = { (byte) 0xEF, (byte) 0xBB, (byte) 0xBF };
        file.write(bom);
        file.write(text);
    }
}
于 2021-06-24T14:03:00.703 回答
0

这是在任何文件上附加 BOM 标头的简单方法:

private static void appendBOM(File file) throws Exception {
    File bomFile = new File(file + ".bom");
    try (FileOutputStream output = new FileOutputStream(bomFile, true)) {
        byte[] bytes = FileUtils.readFileToByteArray(file);
        output.write('\ufeef'); // emits 0xef
        output.write('\ufebb'); // emits 0xbb
        output.write('\ufebf'); // emits 0xbf
        output.write(bytes);
        output.flush();
    }
    
    file.delete();
    bomFile.renameTo(file);
}
于 2020-12-22T15:24:21.357 回答