Конструкторы безопасного кодирования
Заставить 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 с полной обработкой исключений :
Process
slave_process = Runtime.getRuntime().exec("perl -CS script args");
OutputStream
__bytes_into_his_stdin = slave_process.getOutputStream();
OutputStreamWriter
chars_into_his_stdin = new OutputStreamWriter(
__bytes_into_his_stdin,
Charset.forName("UTF-8").newEncoder()
);
InputStream
__bytes_from_his_stdout = slave_process.getInputStream();
InputStreamReader
chars_from_his_stdout = new InputStreamReader(
__bytes_from_his_stdout,
Charset.forName("UTF-8").newDecoder()
);
InputStream
__bytes_from_his_stderr = slave_process.getErrorStream();
InputStreamReader
chars_from_his_stderr = new InputStreamReader(
__bytes_from_his_stderr,
Charset.forName("UTF-8").newDecoder()
);
Теперь у вас есть три потока символов, все поднимают исключение при кодировании ошибок, соответственно называется chars_into_his_stdin
, chars_from_his_stdout
и chars_from_his_stderr
.
Это лишь немного сложнее, чем то, что вам нужно для решения вашей проблемы, решение которой я дал в первой половине этого ответа. Ключевым моментом является то, что это единственный способ обнаружить ошибки кодирования.
Только не заставляйте меня начинать насчет PrintStream
исключений для еды.
InputStreamReader char_input = new InputStreamWriter
следует читать:,InputStreamReader char_input = new InputStreamReader
аInputStreamReader
конструктор принимает, аCharsetDecoder
неCharsetEncoder
.CipherInputStream
, это удалитBadPaddingException
's, даже если они созданы аутентифицированным зашифрованным потоком :(Угробите
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 )
Вам необходимо использовать
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
Также здесь уже был дан ответ на этот вопрос .
источник
InputStreamReader(InputStream in, CharsetDecoder dec)
, чтобы последний аргумент былCharset.forName("UTF-8").newDecoder()
.{In,Out}putStream{Reader,Writer}
конструктора на ошибочных данных, вы обнаружите, что три из них маскируют все исключения, которые должны возникать из-за ошибок кодирования, и только четвертая форма правильно передает их вам. Это тот, который включаетCharset.forName("UTF-8").newDecoder()
. Я немного объясню это в своем ответе.Начиная с Java 11 вы можете:
FileWriter fw = new FileWriter("filename.txt", Charset.forName("utf-8"));
источник
Начиная с Java 7, существует простой способ обработки символьной кодировки BufferedWriter и BufferedReaders. Вы можете создать BufferedWriter напрямую, используя класс Files, вместо создания различных экземпляров Writer. Вы можете просто создать BufferedWriter, который учитывает кодировку символов, вызвав:
Вы можете найти больше об этом в JavaDoc:
источник
С китайским текстом я попытался использовать кодировку UTF-16, и, к счастью, она сработала.
Надеюсь, это поможет!
PrintWriter out = new PrintWriter( file, "UTF-16" );
источник
Хорошо, сейчас 2019 год, и из Java 11 у вас есть конструктор с Charset:
источник
используйте 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();
источник
по моему мнению
Если вы хотите написать следующий код 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();
источник