安全的编码构造函数
让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字符流,并进行全面的异常处理:
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
。 - Mark RhodesCipherInputStream
,它可以移除BadPaddingException
,即使它们是由经过身份验证的加密流创建的 :( - Maarten Bodewes