2016-01-19 22 views
7

Es scheint, dass Files.newBufferedReader() strenger ist über UTF-8 als die naive Alternative.Unterschiedliche Ergebnisse Lesen der Datei mit Files.newBufferedReader() und den Bau Leser direkt

Wenn ich eine Datei mit einem einzigen Byte 128 --- so erstellen, keine gültiges UTF-8-Zeichen --- es wird gerne gelesen werden, wenn ich ein BufferedReader auf einer auf dem Ergebnis der Files.newInputStream()InputStreamReader konstruieren, aber mit Files.newBufferedReader() wird eine Ausnahme ausgelöst.

Dieser Code

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()); 
} 

hat dieses Ergebnis:

� 
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) 

Ist dies dokumentiert? Und ist es möglich, das milde Verhalten mit Files.newBufferedReader() zu bekommen?

+1

Wilder stab im Dunkel, aber haben Sie versucht charset in dem Anruf newBufferedReader Angabe? – JustinKSU

+2

@JustinKSU Er sollte nicht müssen. Diese Methode ist [dokumentiert] (http://docs.oracle.com/javase/8/docs/api/java/nio/file/Files.html#newBufferedReader-java.nio.file.Path-), wenn UTF verwendet wird. 8. – VGR

Antwort

5

Der Unterschied besteht darin, wie die CharsetDecoder verwendeten UTF-8 zu dekodieren, in den beiden Fällen, aufgebaut ist.

Für new InputStreamReader(in, "UTF-8") der Decoder verwendet konstruiert:

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

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

Dies wird ausdrücklich, dass ungültige Sequenzen spezifiziert, wird nur mit dem Standardersatzzeichen ersetzt.

Files.newBufferedReader(path) verwendet:

Charset cs = StandardCharsets.UTF_8; 

CharsetDecoder decoder = cs.newDecoder(); 

In diesem Fall onMalformedInput und onUnmappableCharacter nicht, so dass Sie die Standardaktion erhalten genannt werden, die die Ausnahme werfen Sie sehen.

Es scheint nicht ein Weg, um zu ändern, was Files.newBufferedReader tut. Ich habe nichts dabei gesehen, als ich den Code durchgesehen habe.

5

Von dem, was ich sagen kann, ist es nicht überall dokumentiert, und es ist nicht möglich, newBufferedReader zu bekommen nachsichtig zu verhalten.

Es sollte jedoch dokumentiert werden. In der Tat ist der Mangel an Dokumentation darüber ein gültiger Java-Fehler, selbst wenn die geänderte Dokumentation schließlich sagt, dass "ungültige Zeichensatzfolgen zu undefiniertem Verhalten führen".

Da es keine Dokumentation zu diesem Thema ist, ich glaube nicht, dass Sie sicher auf dem Verhalten verlassen können Sie beobachten. Es ist durchaus möglich, dass eine zukünftige Version von InputStreamReader standardmäßig einen internen CharsetDecoder verwendet, der streng ist.

So nachsichtig Verhalten zu garantieren, würde ich weiter Ihren Code einen Schritt nehmen:

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()); 
}