2016-05-25 14 views
0

Es gibt einige ähnliche Fragen auf der Website, aber alle wurden in verschiedenen Szenarien verwendet. Also, ich frage es hier:Warum liest die FileInputStream read() -Methode ein Fragezeichen falsch (ascii: 63), wenn sie in die Endlosschleife gesetzt wird?

package Assign6B; 

import java.io.FileInputStream; 
import java.io.FileOutputStream; 
import java.io.IOException; 

public class FileOpsDemo { 
    public static void main(String[] args) throws IOException 
    { 

     FileInputStream inputFile = null; 
     FileOutputStream outputFile = null; 

     try 
     { 
      inputFile = new FileInputStream("s:/inputFile.txt"); 
      outputFile = new FileOutputStream("s:/outputFile.txt"); 
      char c; 
      while((c = (char) inputFile.read()) != -1) 
      { 
       System.out.println((char)c); 
       outputFile.write(c); 
      } 

      System.out.println("File transfer complete!"); 
     } 

     finally 
     { 
      if (inputFile != null) 
       inputFile.close(); 

      if (outputFile != null) 
       outputFile.close(); 
     } 
    } 
} 

Das ist mein Code. In der while-Schleife-Bedingung, zuerst hatte ich es gesetzt, um die int-Ausgabe von read() in ein char typisieren. Das Ergebnis war, dass es in eine Endlosschleife ging und alle Zeichen in "?" (ascii: 63). Dann habe ich meinen Fehler bei der Kohle-Konvertierung erkannt und geändert.

Aber wenn ich meine while-Bedingung zu "= -2" (ohne die Char-Konvertierung) geändert hat (diese Bedingung wird nie auftreten und damit in die Endlosschleife). Auch hier werden die ersten (z. B. 10) gültigen Zeichen der Datei noch in "?" Umgewandelt, selbst wenn keine Konvertierung stattfindet. (Nach dem Erreichen von EOF werden alle ungültigen Zeichen zu '?' - ich gehe davon aus, dass dies gegeben ist).

Warum passiert das? Zumindest die gültigen Zeichen der Datei sollten richtig gelesen werden, bis sie auf den EOF stoßen und sich mit ungültigen Zeichen versorgen!

Antwort

0

Ändern Sie einfach diesen Abschnitt des Codes - sobald Sie in ein Zeichen konvertieren, können Sie es nicht erfolgreich mit einer Ganzzahl vergleichen, so dass Ihre while-exit-Bedingung nie erfüllt wird.

int c; 
while ((c = inputFile.read()) != -1) { 
    System.out.println((char) c); 
    outputFile.write(c); 
} 

auch die Java-8 java.nio und java.io Pakete mit viel einfacher

public static void main(String[] args) throws IOException { 
    List<String> lines = Files.readAllLines(Paths.get("s:/inputFile.txt")); 
    Files.write(Paths.get("s:/outputFile.txt"), lines); 
} 
0

typecasting ein das Ergebnis in.read() ist schlechter Stil verkohlen. Zeichen sollten nur von einem Reader lesen - in Ihrem Fall, dass Sie ein Input verwenden:

inputFile = new FileInputStream("s:/inputFile.txt"); 
    outputFile = new FileOutputStream("s:/outputFile.txt"); 
    Reader inputReader = InputStreamReader(inputFile, StandardCharsets.UTF_8); 
    Writer outputWriter = OutputStreamWriter(outputFile, StandardCharsets.UTF_8); 
    char[] cbuf = new char[4096]; 
    int read; 
    while((read = inputReader.read(cbuf)) >= 0) 
    { 
     System.out.println(new String(cbuf, 0, read)); 
     outputWriter.write(cbuf, 0, read); 
    } 

Dieses Beispiel weiterhin kopiert nicht Byte-für-Byte (massive Verbesserung der Geschwindigkeit), und es gilt UTF-8 als Zeichensatz.

+0

* "ein das Ergebnis der in.read typecasting() zu char ist schlechter Stil. "* - Nicht nur schlechter Stil. Abhängig von der tatsächlichen Dateicodierung kann es einfach falsch sein. –

+0

Auch das Schreiben von UTF-8 ist wahrscheinlich eine schlechte Idee. Eine sicherere Annahme wäre, den Plattform-Standardzeichensatz zum Lesen und Schreiben zu verwenden. –

1

Warum passiert das?

Das Problem ist in dieser Zeile:

while((c = (char) inputFile.read()) != -1) 

Sie tun das folgende:

  1. ein Byte aus der Datei lesen. Dies gibt Ihnen eine int, die entweder ein Byte im Bereich von 0 bis 255 oder -1 ist.

  2. Sie geben diesen Wert an eine char. Für das Byte ergibt das einen char Wert im Bereich von 0 bis 255. Für -1 liefert der Cast '\uffff'.

  3. Diesen Wert können Sie c zuweisen.

  4. Dann testen Sie den Wert gegen -1. Hier läuft es schief. In dem Fall, in dem read-1 zurückgegeben wird, werden Sie jetzt diese '\uffff' == -1 bewerten. Die LHS wird in einen int Wert umgewandelt ... 0x0000ffff ... und das wird verglichen mit 0xffffffff.Sie sind anders.

Dann drucken Sie 'uffff' ... die zu einem '?' umgewandelt wird, wenn die Ausgabe als ein Zeichen in Ihrem Standard-charset.


Es gibt zwei große Fehler im Code. Erstens, die Umwandlung int ->char ->int wird nicht funktionieren; siehe oben.

Zweitens und wichtiger:

  • Sie sollten nicht einen Inputstream verwenden werden versuchen, (das Byte ausgerichtet ist) Daten als Zeichen zu lesen, und

  • sollten Sie schreiben werden versuchen, Zeichendaten zu einem OutputStream.

Je nachdem, was Sie eigentlich hier zu erreichen versuchen, sollten Sie entweder:

  • Lese- und Schreib Bytes ... ohne störende „Umwandlung“ zu char in der Mitte oder

  • Verwenden Sie eine FileReader und FileWriter, um die Konvertierungen richtig für die Plattform Standardzeichensatz zu tun.

(Es gibt einige andere Punkte, die über Pufferung gemacht werden könnten, eine alternative charset Wahl, usw., aber diese Antwort schon immer zu lang.)

+0

Diese Logik funktioniert, wenn der FIS "-1" EOF liest. Aber ich bekomme alle Zeichenausgabe auf -1 (und daher die?), Sogar die gültigen Zeichen der Datei ... warum liest es EOF für die gültigen Zeichen der Datei .. oder ist es etwas, das ich hier vermisse? –

+0

Ich denke, dass Sie Dinge falsch interpretieren. 1) Es ist unmöglich, dass ein 'char'' -1' ist, weil 'char' ein >> vorzeichenloser << Typ ist. 2) Wenn bei der Ausgabe ein 'char' in' '' konvertiert wird, bedeutet dies, dass der Zeichenwert (was auch immer es ist) keine gültige Codierung in dem verwendeten Zeichencodierungsschema aufweist. Sie können nicht schließen, was sein tatsächlicher Wert war. –