Holen Sie sich einen OutputStream in einen String

580

Was ist der beste Weg, um die Ausgabe von einem java.io.OutputStream an einen String in Java weiterzuleiten?

Angenommen, ich habe die Methode:

  writeToStream(Object o, OutputStream out)

Womit bestimmte Daten vom Objekt in den angegebenen Stream geschrieben werden. Ich möchte diese Ausgabe jedoch so einfach wie möglich in einen String umwandeln.

Ich denke darüber nach, eine Klasse wie diese zu schreiben (ungetestet):

class StringOutputStream extends OutputStream {

  StringBuilder mBuf;

  public void write(int byte) throws IOException {
    mBuf.append((char) byte);
  }

  public String getString() {
    return mBuf.toString();
  }
}

Aber gibt es einen besseren Weg? Ich möchte nur einen Test durchführen!

Adrian Mouat
quelle
6
Haben Sie nur ASCII-Bytes? Benötigen Sie keine Codepage?
Horcrux7
In diesem Fall ja. Guter Punkt - ich hatte nicht darüber nachgedacht.
Adrian Mouat

Antworten:

607

Ich würde ein verwenden ByteArrayOutputStream. Und am Ende können Sie anrufen:

new String( baos.toByteArray(), codepage );

oder besser:

baos.toString( codepage );

Für den StringKonstruktor codepagekann dies eine Stringoder eine Instanz von java.nio.charset.Charset sein . Ein möglicher Wert ist java.nio.charset.StandardCharsets.UTF_8 .

Die Methode toString()akzeptiert nur a Stringals codepageParameter (Stand Java 8).

Horkrux7
quelle
8
ByteArrayOutputStream hat keine toArray () -Methode. es muss allerdings toByteArray () sein. Können Sie die Antwort korrigieren? Verwenden Sie auch baos.toString (String charsetName), was etwas einfacher wäre.
Jonik
35
Ein Bytearray besteht nur aus Binärdaten. Da (Unicode-) Text auf viele verschiedene Arten binär codiert werden kann, muss der ByteArrayOutputStream wissen, welche Codierung zum Codieren der Bytes verwendet wurde, damit er die Bytes erneut in eine Zeichenfolge decodieren kann. Es ist nicht ratsam, einfach toString ohne Argument zu verwenden, da Sie das Problem einfach ignorieren, anstatt es anzugehen. Java verwendet die Plattformcodierung, die korrekt sein könnte ... oder nicht. Es ist im Grunde zufällig. Sie müssen herausfinden, mit welcher Codierung der Text in Bytes geschrieben wurde, und diese Codierung an String übergeben.
Stijn de Witt
10
Nur eine Klarstellung auf der Codepage, auf die hier verwiesen wird: In Java können Sie Charset.defaultCharset () oder Charset.forName ("spezifischer Zeichensatz") verwenden; Was für mich funktioniert hat war: neuer String (baos.toByteArray (), Charset.defaultCharset ());
Wallace Brown
7
@WallaceBrown mit defaultCharsetist nicht besser als den Zeichensatz insgesamt zu ignorieren - Sie müssen herausfinden, was es ist, bevor Sie verwendentoString
Artbristol
4
StandardCharsets.UTF_8ist ein Charset, kein String. Außerdem wird der Parameter charsetNamenicht aufgerufen codepage.
OrangeDog
46

Ich mag die Apache Commons IO-Bibliothek. Schauen Sie sich die Version von ByteArrayOutputStream an , die auch eine toString(String enc)Methode enthält toByteArray(). Durch die Verwendung vorhandener und vertrauenswürdiger Komponenten wie des Commons-Projekts kann Ihr Code kleiner und einfacher erweitert und für andere Zwecke verwendet werden.

Joe Liversedge
quelle
10
Sparen Sie sich ein Jahr Ihres Lebens und lesen Sie alle gängigen APIs durch. Wenn Sie also auf ein Problem stoßen, können Sie eine vollständig getestete und von der Community betriebene Lösung entwickeln.
Bob Herrmann
15
Hmm, ich bin ein begeisterter Apache Commons-Benutzer, aber in diesem Fall verstehe ich nicht, warum Sie den ByteArrayOutputStream von Commons IO anstelle von JDKs eigenem java.io.ByteArrayOutputStream verwenden sollten. Letzteres bietet auch die Methoden toString (String charsetName) und toByteArray (). Möchtest du das näher erläutern?
Jonik
1
Ja, da der ursprüngliche Kontext eine bessere Möglichkeit zum Streamen und Extrahieren von Inhalten war, habe ich das Commons IO-Beispiel eingefügt, da es eine Schreibmethode (InputStream) für einen damals undefinierten / fragwürdigen Mechanismus zum Auffüllen des OutputStream enthielt. Ich würde auch mit dem JDK gehen.
Joe Liversedge
23

Das hat gut funktioniert

OutputStream output = new OutputStream() {
    private StringBuilder string = new StringBuilder();

    @Override
    public void write(int b) throws IOException {
        this.string.append((char) b );
    }

    //Netbeans IDE automatically overrides this toString()
    public String toString() {
        return this.string.toString();
    }
};

Methodenaufruf = >> marshaller.marshal( (Object) toWrite , (OutputStream) output);

Um die Zeichenfolge zu drucken oder abzurufen, verweisen Sie einfach auf den "Ausgabe" -Stream selbst. Beispiel: Drucken Sie die Zeichenfolge auf console = >> aus System.out.println(output);

Zu Ihrer Information: Mein Methodenaufruf marshaller.marshal(Object,Outputstream)ist für die Arbeit mit XML. Es ist für dieses Thema irrelevant.

Dies ist für den produktiven Gebrauch sehr verschwenderisch, es gibt viel zu viele Konvertierungen und es ist ein bisschen locker. Dies wurde nur codiert, um Ihnen zu beweisen, dass es durchaus möglich ist, einen benutzerdefinierten OuputStream zu erstellen und eine Zeichenfolge auszugeben. Aber gehen Sie einfach Horcrux7 Weg und alles ist gut mit nur zwei Methodenaufrufen.

Und die Welt lebt an einem anderen Tag ...

MS
quelle
9
Nur ein Byte in char umzuwandeln, funktioniert nur bei ASCII. Verwenden Sie ByteArrayOutputStream wie Horcrux7
Dave Ray
2
Einverstanden mit Dave Ray. Sie können nicht davon ausgehen, dass Ihr Byte ein ASCII-Zeichen ist. Sie müssen die Bytes mithilfe einer Codierung interpretieren. Verwenden Sie byteArrayOutputStream.toString ("UTF-8") oder einen neuen String (byteArrayOutputStream.toByteArray (), "UTF-8").
Martin Dow
16

Folgendes habe ich getan:

Obj.writeToStream(toWrite, os);
try {
    String out = new String(os.toByteArray(), "UTF-8");
    assertTrue(out.contains("testString"));
} catch (UnsupportedEncondingException e) {
    fail("Caught exception: " + e.getMessage());
}

Wo os ist ein ByteArrayOutputStream.

Adrian Mouat
quelle
2
@ JavaJigs Ich habe dies am Ende meiner Antwort vor fast 5 Jahren geklärt :)
Adrian Mouat
19
Betrachten Sie ersetzen "UTF-8"mit StandardCharsets.UTF_8.
James.garriss
0
baos.toString(StandardCharsets.UTF_8);

Konvertiert den Inhalt des Puffers in eine Zeichenfolge, indem die Bytes mit dem angegebenen Zeichensatz dekodiert werden.

Java 14 - https://docs.oracle.com/

jschnasse
quelle