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?

Andrei Savu
quelle

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.

Peter
quelle
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"))
Ritesh Tendulkar
quelle
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.

Peter Ford
quelle
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.

Phil Harvey
quelle
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.

Oliv
quelle
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.

Tom Hawtin - Tackline
quelle
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
5

Sie können Probleme mit der Textcodierung nicht vermeiden, Apache commons-io jedoch

Beachten Sie, dass dies die Bibliotheken sind, auf die in Peters Antwort von koders.com Bezug genommen wird, sondern nur Links zur Bibliothek anstelle des Quellcodes.

dfrankow
quelle
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
Sam Barnum
quelle
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

Romeara
quelle
-1

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

InputStream s = new BufferedInputStream( new ReaderInputStream( new StringReader("a string")));
Aaron
quelle
6
ReaderInputStream befindet sich in Apache Commons IO.
Will Beason