2016-01-19 202 views
7

對於UTF-8,Files.newBufferedReader()似乎比天真的選擇更爲嚴格。使用Files.newBufferedReader()讀取文件的不同結果並直接構建讀取器

如果我創建一個字節128文件---所以,不是一個合法的UTF-8字符---它會很高興,如果我對Files.newInputStream()結果上InputStreamReader構建BufferedReader閱讀,但Files.newBufferedReader()引發異常。

此代碼

try (
    InputStream in = Files.newInputStream(path); 
    Reader isReader = new InputStreamReader(in, "UTF-8"); 
    Reader reader = new BufferedReader(isReader); 
) { 
    System.out.println((char) reader.read()); 
} 

try (
    Reader reader = Files.newBufferedReader(path); 
) { 
    System.out.println((char) reader.read()); 
} 

有這樣的結果:

� 
Exception in thread "main" 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.InputStreamReader.read(InputStreamReader.java:184) 
    at java.io.BufferedReader.fill(BufferedReader.java:161) 
    at java.io.BufferedReader.read(BufferedReader.java:182) 
    at TestUtf8.main(TestUtf8.java:28) 

是這個記錄?是否有可能通過Files.newBufferedReader()獲得寬大的行爲?

+1

野生刺在黑暗中,但你有沒有試過在newBufferedReader調用指定字符集? – JustinKSU

+2

@JustinKSU他不應該。該方法[記錄](http://docs.oracle.com/javase/8/docs/api/java/nio/file/Files.html#newBufferedReader-java.nio.file.Path-)與使用UTF- 8。 – VGR

回答

5

區別在於如何在兩種情況下構造用於解碼UTF-8的CharsetDecoder

對於new InputStreamReader(in, "UTF-8")解碼器使用構建:

Charset cs = Charset.forName("UTF-8"); 

CharsetDecoder decoder = cs.newDecoder() 
      .onMalformedInput(CodingErrorAction.REPLACE) 
      .onUnmappableCharacter(CodingErrorAction.REPLACE); 

這是明確指定了無效的序列與標準替換字符只是代替。

Files.newBufferedReader(path)用途:

Charset cs = StandardCharsets.UTF_8; 

CharsetDecoder decoder = cs.newDecoder(); 

在這種情況下onMalformedInputonUnmappableCharacter沒有被調用,所以你得到默認的作用,這是拋出您所看到的例外。

似乎沒有辦法改變Files.newBufferedReader的功能。在查看代碼時,我沒有看到任何記錄。

5

從我所知道的,它沒有記錄在任何地方,並且不可能讓newBufferedReader表現得寬鬆。

但應該記錄下來。事實上,即使修改過的文檔最終說「無效的charset序列導致未定義的行爲」,但缺乏關於它的文檔是一個有效的Java錯誤。

此外,由於沒有關於該主題的文檔,我不認爲您可以安全地依賴您正在觀察的行爲。未來版本的InputStreamReader完全有可能默認使用嚴格的內部CharsetDecoder。

所以,爲了保證寬鬆的行爲,我會拿你的代碼更遠了一步:

try (
    InputStream in = Files.newInputStream(path); 
    CharsetDecoder decoder = StandardCharsets.UTF_8.newDecoder(); 
    decoder.onMalformedInput(CodingErrorAction.REPLACE); 
    Reader isReader = new InputStreamReader(in, decoder); 
    Reader reader = new BufferedReader(isReader); 
) { 
    System.out.println((char) reader.read()); 
}