Wie konvertiere ich einen Reader in InputStream und einen Writer in OutputStream?


87

Gibt es eine einfache Möglichkeit, Probleme mit der Textcodierung zu vermeiden?

Antworten:


45

Sie können es nicht wirklich vermeiden, sich mit den Problemen der Textcodierung zu befassen, aber in Apache Commons gibt es bereits Lösungen:

Sie müssen nur die Codierung Ihrer Wahl auswählen.


7
Zu Ihrer Information: Der ReaderInputStream-Code weist einen Fehler beim Lesen von Bytes auf (er funktioniert nicht für alle Codierungen). Beweis: illegalargumentexception.blogspot.com/2009/05/… Es gibt einen offenen Fehler: issue.apache.org/bugzilla/show_bug.cgi?id=40455
McDowell

1
Sie finden die Klassen in Apaches Commons-Io-Bibliothek: commons.apache.org/proper/commons-io
AlikElzin-kilaka

@McDowell, der von Ihnen erwähnte Fehler ist in der Implementierung von Apache Ant, nicht in Commons-Io, daher ist er für diese Antwort nicht relevant.
Roman

94

Wenn Sie mit einem String beginnen, können Sie auch Folgendes tun:

new ByteArrayInputStream(inputString.getBytes("UTF-8"))

7
Eine gute ReaderInputStreamImplementierung würde weniger Speicher erfordern - es sollten nicht alle Bytes gleichzeitig in einem Array gespeichert werden müssen.
Piotr Findeisen

3
Ich mag diese Lösung, weil sie funktioniert, wenn Sie einen Unit-Test-Code benötigen, der Eingaben für (z. B.) Standardeingaben akzeptiert.
Kedar Mhaswade

42

Nun, ein Reader befasst sich mit Zeichen und ein InputStream mit Bytes. Die Codierung gibt an, wie Sie Ihre Zeichen als Bytes darstellen möchten, sodass Sie das Problem nicht wirklich ignorieren können. Um Probleme zu vermeiden, ist meine Meinung: Wählen Sie einen Zeichensatz (z. B. "UTF-8") und bleiben Sie dabei.

Wie bereits erwähnt, lauten die offensichtlichen Namen für diese Klassen ReaderInputStream und WriterOutputStream . Überraschenderweise sind diese nicht in der Java-Bibliothek enthalten , obwohl die entgegengesetzten Klassen InputStreamReader und OutputStreamWriter verwendet werden inbegriffen.

Viele Leute haben sich ihre eigenen Implementierungen ausgedacht, einschließlich Apache Commons IO . Abhängig von Lizenzproblemen können Sie wahrscheinlich die Commons-Io-Bibliothek in Ihr Projekt aufnehmen oder sogar einen Teil des Quellcodes kopieren (der hier heruntergeladen werden kann ).

Wie Sie sehen können, heißt es in der Dokumentation beider Klassen, dass "alle von der JRE unterstützten Zeichensatzcodierungen korrekt behandelt werden".

NB Ein Kommentar zu einer der anderen Antworten hier erwähnt diesen Fehler . Dies betrifft jedoch die Apache Ant ReaderInputStream-Klasse ( hier ) und nicht die Apache Commons IO ReaderInputStream-Klasse.


19

Beachten Sie außerdem, dass Sie, wenn Sie mit einem String beginnen, das Erstellen eines StringReader überspringen und in einem Schritt einen InputStream erstellen können, indem Sie org.apache.commons.io.IOUtils von Commons IO wie folgt verwenden :

InputStream myInputStream = IOUtils.toInputStream(reportContents, "UTF-8");

Natürlich müssen Sie noch über die Textcodierung nachdenken, aber zumindest erfolgt die Konvertierung in einem Schritt.


4
Diese Methode umfasst im Wesentlichen new ByteArrayInputStream(report.toString().getBytes("utf-8"))die Zuweisung von zwei zusätzlichen Kopien des Berichts im Speicher. Wenn der Bericht groß ist, ist er schlecht. Siehe meine Antwort.
Oliv

8

Verwenden:

new CharSequenceInputStream(html, StandardCharsets.UTF_8);

Auf diese Weise ist keine Vorabkonvertierung nach Stringund dann nach erforderlich byte[], wodurch viel mehr Heapspeicher zugewiesen wird, falls der Bericht groß ist. Es wird im laufenden Betrieb in Bytes konvertiert, wenn der Stream direkt aus dem StringBuffer gelesen wird.

Es verwendet CharSequenceInputStream aus dem Apache Commons IO-Projekt.



5

Die offensichtlichen Namen für diese Klassen sind ReaderInputStream und WriterOutputStream. Leider sind diese nicht in der Java-Bibliothek enthalten. Google ist jedoch dein Freund.

Ich bin mir nicht sicher, ob es alle alptraumhaften Textcodierungsprobleme umgehen wird.

Es gibt eine RFE, jedoch geschlossen ist und nicht behoben werden kann.


1
bugs.openjdk.java.net/browse/JDK-4103785 enthält den Kommentar "Wir haben eine öffentliche API für die Zeichensatzcodierung ... kein zwingender Grund, diese Klassen hinzuzufügen" - wie macht man das in Java 7 ohne zusätzliche Bibliotheken, zwölf Jahre später?
Piotr Findeisen


4

Versuchen Sie, den Inhalt von a Readerin ein zu schreiben OutputStream? In diesem Fall fällt es Ihnen leichter , das s OutputStreamin ein zu wickeln OutputStreamWriterund das chars von dem Readerin das zu schreiben Writer, anstatt zu versuchen, den Reader in einen zu konvertieren InputStream:

final Writer writer = new BufferedWriter(new OutputStreamWriter( urlConnection.getOutputStream(), "UTF-8" ) );
int charsRead;
char[] cbuf = new char[1024];
while ((charsRead = data.read(cbuf)) != -1) {
    writer.write(cbuf, 0, charsRead);
}
writer.flush();
// don't forget to close the writer in a finally {} block

1

Eine Warnung bei Verwendung von WriterOutputStream - das Schreiben von Binärdaten in eine Datei wird nicht immer ordnungsgemäß ausgeführt / genauso wie bei einem normalen Ausgabestream. Ich hatte ein Problem damit, das ich eine Weile brauchte, um es aufzuspüren.

Wenn Sie können, würde ich empfehlen, einen Ausgabestream als Basis zu verwenden. Wenn Sie Zeichenfolgen schreiben müssen, verwenden Sie dazu einen OUtputStreamWriter-Wrapper um den Stream. Das Konvertieren von Text in Bytes ist weitaus zuverlässiger als umgekehrt, weshalb WriterOutputStream wahrscheinlich nicht Teil der Standard-Java-Bibliothek ist



-1

Zum Lesen eines Strings in einem Stream mit genau dem, was Java liefert.

InputStream s = new BufferedInputStream( new ReaderInputStream( new StringReader("a string")));

6
ReaderInputStream befindet sich in Apache Commons IO.
Will Beason
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.