使用FileWriter(Java)以UTF-8编写文件?

use*_*970 74 java unicode file-io file-format utf-8

我有以下代码,但我希望它写为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();
}
Run Code Online (Sandbox Code Playgroud)

tch*_*ist 72

安全编码构造函数

让Java正确地通知您编码错误是很棘手的.您必须使用最详细的,唉,四个备用结构中使用最少的每个结构,InputStreamReaderOutputStreamWriter在编码故障上接收适当的异常.

对于文件I/O,始终确保始终使用两者作为第二个参数OutputStreamWriterInputStreamReader花式编码器参数:

  Charset.forName("UTF-8").newEncoder()
Run Code Online (Sandbox Code Playgroud)

还有其他更好的可能性,但三种更简单的可能性都不适用于异常处理.这样做:

 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() 
 );
Run Code Online (Sandbox Code Playgroud)

至于跑步

 $ java -Dfile.encoding=utf8 SomeTrulyRemarkablyLongcLassNameGoeShere
Run Code Online (Sandbox Code Playgroud)

问题是,不会对字符流使用完整的编码器参数形式,因此您将再次错过编码问题.

更长的例子

这是一个较长的例子,这个管理一个进程而不是一个文件,我们将两个不同的输入字节流和一个输出字节流全部提升为UTF-8字符流,并完全处理异常:

 // this runs a perl script with UTF-8 STD{IN,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()
                         );
Run Code Online (Sandbox Code Playgroud)

现在,你有三个字符流,所有引发异常的编码错误,分别称为chars_into_his_stdin,chars_from_his_stdoutchars_from_his_stderr.

这只是你的问题所需要的稍微复杂一点,我在这个答案的前半部分给出了解决方案.关键是这是检测编码错误的唯一方法.

只是不要让我开始讨论PrintStream吃异常.

  • (整个Java IO系统一直都是一团糟。应该像Joda Time返工日期一样彻底返工。) (2认同)

Mic*_*rdt 49

Ditch FileWriterFileReader,它们是无用的,因为它们不允许您指定编码.相反,使用

new OutputStreamWriter(new FileOutputStream(file), StandardCharsets.UTF_8)

new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8);

  • 如果你不使用非常详细的`Charset.forName("UTF-8").newDecoder()`参数(或一些更高级的构造)而不只是"UTF-8",你就不会得到适当的通知编码错误(读取:异常将被抑制,它将神秘地隐藏编码错误). (11认同)
  • `new OutputStreamWriter(new FileOutputStream(file),StandardCharsets.UTF_8)` (3认同)

Edw*_*rzo 44

您需要使用OutputStreamWriter该类作为您的编写器参数BufferedWriter.它确实接受编码.查看javadocs.

有点像这样:

BufferedWriter out = new BufferedWriter(new OutputStreamWriter(
    new FileOutputStream("jedis.txt"), "UTF-8"
));
Run Code Online (Sandbox Code Playgroud)

或者,您可以将系统属性的当前系统编码设置file.encoding为UTF-8.

java -Dfile.encoding=UTF-8 com.jediacademy.Runner arg1 arg2 ...
Run Code Online (Sandbox Code Playgroud)

您也可以在运行时将其设置为系统属性,System.setProperty(...)如果您只需要此特定文件,但在这种情况下我认为我更喜欢OutputStreamWriter.

通过设置您可以使用的系统属性,FileWriter并期望它将使用UTF-8作为文件的默认编码.在这种情况下,您可以读取和写入所有文件.

编辑

  • 从API 19开始,您可以将字符串"UTF-8"替换为 StandardCharsets.UTF_8

  • 正如tchrist在下面的评论中所建议的那样,如果您打算在文件中检测编码错误,您将被迫使用该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));
    
    Run Code Online (Sandbox Code Playgroud)

    您可以选择不同的操作 IGNORE | REPLACE | REPORT

此外,这个问题已在这里得到解答.

  • @edalorzo如果你在错误数据上测试了四个不同的`{In,Out} putStream {Reader,Writer}`构造函数,你会发现其中三个**掩盖所有异常****应该*来自编码错误,只有第四种形式正确地将它们传递给您.那是涉及`Charset.forName("UTF-8").newDecoder()`的那个.我在答案中解释了一下. (3认同)

小智 9

从 Java 7 开始,有一种简单的方法来处理 BufferedWriter 和 BufferedReaders 的字符编码。您可以通过使用 Files 类而不是创建 Writer 的各种实例来直接创建 BufferedWriter。您可以简单地创建一个考虑字符编码的 BufferedWriter,方法是调用:

Files.newBufferedWriter(file.toPath(), StandardCharsets.UTF_8);
Run Code Online (Sandbox Code Playgroud)

您可以在 JavaDoc 中找到更多相关信息:


Phu*_*ong 5

有了中文文本,我尝试使用Charset UTF-16,幸运的是它有效.

希望这可以帮助!

PrintWriter out = new PrintWriter( file, "UTF-16" );
Run Code Online (Sandbox Code Playgroud)


mor*_*nsi 5

从Java 11开始,您可以执行以下操作:

FileWriter fw = new FileWriter("filename.txt", Charset.forName("utf-8"));
Run Code Online (Sandbox Code Playgroud)