使用 FileWriter (Java) 以 UTF-8 格式写入文件?
Posted
技术标签:
【中文标题】使用 FileWriter (Java) 以 UTF-8 格式写入文件?【英文标题】:Write a file in UTF-8 using FileWriter (Java)? 【发布时间】:2012-04-08 19:49:56 【问题描述】:但是,我有以下代码,我希望它写为 UTF-8 文件来处理外来字符。有没有办法做到这一点,是否需要有一个参数?
非常感谢您对此提供的帮助。谢谢。
try
BufferedReader reader = new BufferedReader(new FileReader("C:/Users/Jess/My Documents/actresses.list"));
writer = new BufferedWriter(new FileWriter("C:/Users/Jess/My Documents/actressesFormatted.csv"));
while( (line = reader.readLine()) != null)
//If the line starts with a tab then we just want to add a movie
//using the current actor's name.
if(line.length() == 0)
continue;
else if(line.charAt(0) == '\t')
readMovieLine2(0, line, surname.toString(), forename.toString());
//Else we've reached a new actor
else
readActorName(line);
catch (IOException e)
e.printStackTrace();
【问题讨论】:
【参考方案1】:安全编码构造函数
让 Java 正确地通知您编码错误是很棘手的。对于InputStreamReader
和OutputStreamWriter
中的每一个,您必须使用四个备用构造函数中最冗长的 以及最少使用收到有关编码故障的适当异常。
对于文件 I/O,始终确保始终将花哨的编码器参数用作 OutputStreamWriter
和 InputStreamReader
的第二个参数:
Charset.forName("UTF-8").newEncoder()
还有其他更奇特的可能性,但三种更简单的可能性都不适用于异常处理。这些可以:
OutputStreamWriter char_output = new OutputStreamWriter(
new FileOutputStream("some_output.utf8"),
Charset.forName("UTF-8").newEncoder()
);
InputStreamReader char_input = new InputStreamReader(
new FileInputStream("some_input.utf8"),
Charset.forName("UTF-8").newDecoder()
);
至于运行
$ java -Dfile.encoding=utf8 SomeTrulyRemarkablyLongcLassNameGoeShere
问题在于,它不会对字符流使用完整的编码器参数形式,因此您将再次错过编码问题。
更长的例子
这是一个更长的例子,这个例子管理一个进程而不是一个文件,我们将两个不同的输入字节流和一个输出字节流全部提升为 UTF-8 字符流具有完整的异常处理:
// this runs a perl script with UTF-8 STDIN,OUT,ERR streams
Process
slave_process = Runtime.getRuntime().exec("perl -CS script args");
// fetch his stdin byte stream...
OutputStream
__bytes_into_his_stdin = slave_process.getOutputStream();
// and make a character stream with exceptions on encoding errors
OutputStreamWriter
chars_into_his_stdin = new OutputStreamWriter(
__bytes_into_his_stdin,
/* DO NOT OMIT! */ Charset.forName("UTF-8").newEncoder()
);
// fetch his stdout byte stream...
InputStream
__bytes_from_his_stdout = slave_process.getInputStream();
// and make a character stream with exceptions on encoding errors
InputStreamReader
chars_from_his_stdout = new InputStreamReader(
__bytes_from_his_stdout,
/* DO NOT OMIT! */ Charset.forName("UTF-8").newDecoder()
);
// fetch his stderr byte stream...
InputStream
__bytes_from_his_stderr = slave_process.getErrorStream();
// and make a character stream with exceptions on encoding errors
InputStreamReader
chars_from_his_stderr = new InputStreamReader(
__bytes_from_his_stderr,
/* DO NOT OMIT! */ Charset.forName("UTF-8").newDecoder()
);
现在您有了三个在编码错误时都会引发异常的字符流,分别称为chars_into_his_stdin
、chars_from_his_stdout
和chars_from_his_stderr
。
这仅比您解决问题所需的复杂一些,我在此答案的前半部分给出了解决方案。关键是这是检测编码错误的唯一方法。
请不要让我开始谈论 PrintStream
s 饮食异常。
【讨论】:
很好的答案,但我认为它有一个小错误 -InputStreamReader char_input = new InputStreamWriter
应该读作:InputStreamReader char_input = new InputStreamReader
,InputStreamReader
构造函数采用CharsetDecoder
,而不是CharsetEncoder
。
但这是一个真正的问题吗,UTF-8 无法表示什么,我认为它可以编码任何东西。
如果您想抱怨 Streams 吃异常,请尝试 CipherInputStream
,它会删除 BadPaddingException
,即使它们是由经过身份验证的密码流创建的 :(
我在您的代码中发现了一个小错误:"Charset.forName("UTF-8").newEncoder()" for "InputStreamReader" 应该是 "Charset.forName("UTF-8") .newDecoder()”。所以“解码器”而不是“编码器”。但无论如何,感谢这个不错的答案和+1。 :)
(整个 Java IO 系统一直都是一团糟。应该像 Joda Time 重做日期一样彻底重做。)【参考方案2】:
抛弃FileWriter
和FileReader
,它们完全没用,因为它们不允许您指定编码。相反,使用
new OutputStreamWriter(new FileOutputStream(file), StandardCharsets.UTF_8)
和
new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8);
【讨论】:
如果您不使用非常冗长的Charset.forName("UTF-8").newDecoder()
参数(或一些更高级的构造)而不仅仅是"UTF-8"
,您将不会收到正确的编码错误通知(阅读:异常将是被抑制,它会神秘地隐藏编码错误)。
new OutputStreamWriter(new FileOutputStream(file), StandardCharsets.UTF_8 )
【参考方案3】:
您需要使用OutputStreamWriter
类作为BufferedWriter
的写入器参数。它确实接受编码。为它查看javadocs。
有点像这样:
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(
new FileOutputStream("jedis.txt"), "UTF-8"
));
或者您可以使用系统属性file.encoding
将当前系统编码设置为UTF-8。
java -Dfile.encoding=UTF-8 com.jediacademy.Runner arg1 arg2 ...
如果您只需要此特定文件,您也可以在运行时使用System.setProperty(...)
将其设置为系统属性,但在这种情况下,我认为我更喜欢OutputStreamWriter
。
通过设置系统属性,您可以使用FileWriter
并期望它将使用 UTF-8 作为文件的默认编码。在这种情况下,适用于您读取和写入的所有文件。
编辑
从 API 19 开始,您可以将字符串“UTF-8”替换为 StandardCharsets.UTF_8
正如tchrist 在下面的 cmets 中所建议的那样,如果您打算检测文件中的编码错误,您将不得不使用OutputStreamWriter
方法并使用接收字符集编码器的构造函数。
有点像
CharsetEncoder encoder = Charset.forName("UTF-8").newEncoder();
encoder.onMalformedInput(CodingErrorAction.REPORT);
encoder.onUnmappableCharacter(CodingErrorAction.REPORT);
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("jedis.txt"),encoder));
您可以选择操作IGNORE | REPLACE | REPORT
另外,这个问题已经回答了here。
【讨论】:
这还不够。你还需要一个InputStreamReader(InputStream in, CharsetDecoder dec)
,这样最后一个参数就是Charset.forName("UTF-8").newDecoder()
。
如果您这样做,输入编码错误将被静默删除。
不需要编码器。构造函数在输入/输出类中都接受字符串、字符集或编码器。不知道你的评论是什么意思。请详细说明一下好吗?
@edalorzo 如果您在错误数据上测试四个不同的In,OutputStreamReader,Writer
构造函数,您会发现其中三个屏蔽所有异常应该 i> 由编码错误引起,只有第四种形式正确地将它们传递给您。那就是涉及Charset.forName("UTF-8").newDecoder()
的那个。我在回答中对此做了一些解释。
是的,这样好多了。 更多出现输入编码错误而不是出现输出(至少如果它是 UTF 形式:8 位输出编码总是 lose-lose 在 Unicode 中。)但是,理论上你仍然可以在输出中产生它们,因为 Java 允许不成对的代理项存在于内存中的字符串中(它必须;这不是错误!),但不符合UTF-8,16,32 输出编码器允许在输出时生成它们。【参考方案4】:
从 Java 11 开始,您可以这样做:
FileWriter fw = new FileWriter("filename.txt", Charset.forName("utf-8"));
【讨论】:
【参考方案5】:从 Java 7 开始,有一种简单的方法可以处理 BufferedWriter 和 BufferedReaders 的字符编码。您可以使用 Files 类直接创建 BufferedWriter,而不是创建 Writer 的各种实例。您可以通过调用简单地创建一个考虑字符编码的 BufferedWriter:
Files.newBufferedWriter(file.toPath(), StandardCharsets.UTF_8);
您可以在 JavaDoc 中找到更多相关信息:
Files class Files#newBufferedWriter【讨论】:
【参考方案6】:对于中文文本,我尝试使用 Charset UTF-16,幸运的是它可以工作。
希望这能有所帮助!
PrintWriter out = new PrintWriter( file, "UTF-16" );
【讨论】:
可以试试 UTF-32【参考方案7】:好的,现在是 2019 年,从 Java 11 开始,您有了一个带有 Charset 的构造函数:
FileWriter(String fileName, Charset charset)
不幸的是,我们仍然无法修改字节缓冲区大小,而且它是 设置为 8192。(https://www.baeldung.com/java-filewriter)
【讨论】:
【参考方案8】:使用OutputStream而不是FileWriter来设置编码类型
// file is your File object where you want to write you data
OutputStream outputStream = new FileOutputStream(file);
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream, "UTF-8");
outputStreamWriter.write(json); // json is your data
outputStreamWriter.flush();
outputStreamWriter.close();
【讨论】:
【参考方案9】:在我看来
如果你想写follow kind UTF-8。你应该创建一个字节数组。然后,你可以这样做:
byte[] by=("<?xml version=\"1.0\" encoding=\"utf-8\"?>"+"Your string".getBytes();
然后,您可以将每个字节写入您创建的文件中。 示例:
OutputStream f=new FileOutputStream(xmlfile);
byte[] by=("<?xml version=\"1.0\" encoding=\"utf-8\"?>"+"Your string".getBytes();
for (int i=0;i<by.length;i++)
byte b=by[i];
f.write(b);
f.close();
【讨论】:
欢迎来到 Stack Overflow!虽然这段代码 sn-p 可以解决问题,但including an explanation 确实有助于提高帖子的质量。请记住,您正在为将来的读者回答问题,而这些人可能不知道您的代码建议的原因。也请尽量不要用解释性的 cmets 挤满你的代码,这会降低代码和解释的可读性!以上是关于使用 FileWriter (Java) 以 UTF-8 格式写入文件?的主要内容,如果未能解决你的问题,请参考以下文章
J04-Java IO流总结二《 FileReader和FileWriter 》