Написать файл в UTF-8 с помощью FileWriter (Java)? - PullRequest
71 голосов
/ 24 марта 2012

Однако у меня есть следующий код, и я хочу, чтобы он записывался в виде файла 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();
}

Ответы [ 7 ]

69 голосов
/ 24 марта 2012

Конструкторы безопасного кодирования

Сложно заставить Java правильно уведомлять вас об ошибках кодирования. Вы должны использовать наиболее подробный и, увы, наименее используемый из четырех альтернативных конструкторов для каждого из InputStreamReader и OutputStreamWriter, чтобы получить правильное исключение при сбое кодирования.

Для файлового ввода-вывода всегда обязательно используйте в качестве второго аргумента как 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 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()
                         );

Теперь у вас есть три символьных потока, которые все вызывают исключение при ошибках кодирования, соответственно называемые chars_into_his_stdin, chars_from_his_stdout и chars_from_his_stderr.

Это лишь немного сложнее, чем то, что вам нужно для вашей проблемы, решение которой я дал в первой половине этого ответа. Ключевым моментом является то, что это единственный способ обнаружить ошибки кодирования.

Только не начинайте меня с PrintStream исключений в еде.

48 голосов
/ 24 марта 2012

Ditch FileWriter и FileReader, которые бесполезны именно потому, что они не позволяют указывать кодировку. Вместо этого используйте

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

и

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

43 голосов
/ 24 марта 2012

Вам необходимо использовать класс OutputStreamWriter в качестве параметра записи для вашего BufferedWriter.Он принимает кодировку.Просмотрите javadocs .

Примерно так:

BufferedWriter out = new BufferedWriter(new OutputStreamWriter(
    new FileOutputStream("jedis.txt"), "UTF-8"
));

Или вы можете установить текущую кодировку системы со свойством system 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 , если вы собираетесь обнаруживать ошибки кодирования в вашем файле, вы будете вынуждены использоватьподход 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

Также на этот вопрос уже был дан ответ здесь .

5 голосов
/ 01 марта 2016

С китайским текстом я попытался использовать Charset UTF-16 и, к счастью, он работает.

Надеюсь, это поможет!

PrintWriter out = new PrintWriter( file, "UTF-16" );
3 голосов
/ 18 октября 2017

Начиная с Java 7, существует простой способ обработки кодировки символов BufferedWriter и BufferedReaders.Вы можете создать BufferedWriter напрямую, используя класс Files вместо создания различных экземпляров Writer.Вы можете просто создать BufferedWriter, который учитывает кодировку символов, вызвав:

Files.newBufferedWriter(file.toPath(), StandardCharsets.UTF_8);

Подробнее об этом можно узнать в JavaDoc:

2 голосов
/ 31 октября 2018

Начиная с Java 11 вы можете сделать:

FileWriter fw = new FileWriter("filename.txt", Charset.forName("utf-8"));
0 голосов
/ 20 июня 2017

На мой взгляд

Если вы хотите написать, следуйте виду 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();
...