Конструкторы безопасного кодирования
Заставить 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.