Java 8でファイルを読み込む際に奇妙な動作が発生しました。誰かがそれを理解できるかどうか疑問に思っています。不正な形式のファイルを読み取るときにStreamDecoderとInputStreamReaderを比較する
シナリオ:
不正な形式のテキストファイルを読む。間違った言い方をすれば、それはユニコード・コード・ポイントにマップされないバイトを含んでいることを意味します。次のように
私はそのようなファイルを作成するために使用するコードは次のとおりです。
byte[] text = new byte[1];
char k = (char) -60;
text[0] = (byte) k;
FileUtils.writeByteArrayToFile(new File("/tmp/malformed.log"), text);
このコードは(も拡張1)ASCIIテーブルの一部ではありません、正確に1つのバイトを含むファイルを生成します。
�
UNICODE Replacement Characterです:cat
にこのファイルをしようと
は、次の出力を生成します。 UTF-8は非アスキー文字をデコードするために2バイト必要であるため、これは理にかなっていますが、我々は1つしか持っていません。これは私のJavaコードからも予想される動作です。いくつかの一般的なコードの貼り付け
:ここ
private void read(Reader reader) throws IOException {
CharBuffer buffer = CharBuffer.allocate(8910);
buffer.flip();
// move existing data to the front of the buffer
buffer.compact();
// pull in as much data as we can from the socket
int charsRead = reader.read(buffer);
// flip so the data can be consumed
buffer.flip();
ByteBuffer encode = Charset.forName("UTF-8").encode(buffer);
byte[] body = new byte[encode.remaining()];
encode.get(body);
System.out.println(new String(body));
}
がnio
を使用して、私の最初のアプローチです:
FileInputStream inputStream = new FileInputStream(new File("/tmp/malformed.log"));
read(Channels.newReader(inputStream.getChannel(), "UTF-8");
これは、次の例外を生成します。
java.nio.charset.MalformedInputException: Input length = 1
at java.nio.charset.CoderResult.throwException(CoderResult.java:281)
at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:339)
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178)
at java.io.Reader.read(Reader.java:100)
私が期待したものではありませんどのこれは実際には腐敗しており、違法なfであるため、一種の意味がありますile、例外は基本的にもっと多くのバイトが読み込まれると予想しています。
そして、私の二番目の
(定期java.io
を使用して):
は
FileInputStream inputStream = new FileInputStream(new File("/tmp/malformed.log"));
read(new InputStreamReader(inputStream, "UTF-8"));
これは失敗とcat
とまったく同じ出力を生成しませんでした。また、理にかなっている
�
を。
だから私の質問は以下のとおりです。
- このシナリオでは、Javaアプリケーションからの予想される動作は何ですか?
Channels.newReader
(StreamDecoder
を返す)と、通常のInputStreamReader
を使用するのに違いがあるのはなぜですか?私は何かを読んで間違って何かをしていますか?
説明があれば幸いです。
感謝:)
あなたは 'InputStreamReader'に' UTF-8'を指定していないことに気づいていますか?あなたのプラットフォームのデフォルトのエンコーディングは 'UTF-8'なのでしょうか? 'InputStreamReader'は' StreamDecoder'も内部的に使用します。 – Kayaman
"拡張されたもの":どの拡張? IBM437は、任意の順序で256バイトの値をすべて使用します。とにかく、テキストファイルが不正な形式になるとどう思いますか?あなたのアプリケーションについて、悪い入力を部分的に処理しなければならないことがありますか?アプリケーションがそれを拒否した場合、悪い入力をソースで修正することはできませんか?言い換えれば、MalformedInputExceptionは多くの場合に予想される動作です。 –
@Kayamanありがとう、私はそれに気付かなかった。はい、私のプラットフォームのデフォルトはUTF-8です。私はCharsetを指定するようにコードを変更し、動作は変わりません。 (コードを編集しました) –