Dapatkan OutputStream ke dalam sebuah String

580

Apa cara terbaik untuk mem-pipe output dari java.io.OutputStream ke String di Java?

Katakanlah saya punya metode:

  writeToStream(Object o, OutputStream out)

Yang menulis data tertentu dari objek ke aliran yang diberikan. Namun, saya ingin mendapatkan output ini menjadi String semudah mungkin.

Saya sedang mempertimbangkan untuk menulis kelas seperti ini (belum diuji):

class StringOutputStream extends OutputStream {

  StringBuilder mBuf;

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

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

Tetapi apakah ada cara yang lebih baik? Saya hanya ingin menjalankan tes!

Adrian Mouat
sumber
6
Apakah Anda hanya memiliki ASCII byte? APAKAH Anda tidak perlu Codepage?
Horcrux7
Dalam hal ini, ya. Namun, poin bagus - saya belum memikirkannya.
Adrian Mouat

Jawaban:

607

Saya akan menggunakan ByteArrayOutputStream. Dan pada akhirnya Anda dapat menghubungi:

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

atau lebih baik:

baos.toString( codepage );

Untuk Stringkonstruktor, codepagebisa berupa Stringinstance dari java.nio.charset.Charset . Nilai yang mungkin adalah java.nio.charset.StandardCharsets.UTF_8 .

Metode toString()hanya menerima Stringsebagai codepageparameter (Java berdiri 8).

Horcrux7
sumber
8
ByteArrayOutputStream tidak memiliki metode toArray (); itu memang harus toByteArray (). Bisakah Anda memperbaiki jawabannya? Juga, mengapa tidak menggunakan baos.toString (String charsetName) yang akan sedikit lebih sederhana.
Jonik
35
Bytearray hanyalah data biner. Karena teks (unicode) dapat disandikan biner dengan berbagai cara, ByteArrayOutputStream perlu mengetahui pengkodean apa yang digunakan untuk menyandikan byte, sehingga dapat menggunakan pengkodean yang sama untuk mendekode byte ke string lagi. Cukup menggunakan toString tanpa argumen tidak bijaksana karena Anda mengabaikan masalah alih-alih menanganinya; Java akan menggunakan pengkodean platform yang mungkin benar ... atau tidak. Ini pada dasarnya acak. Anda perlu mengetahui pengkodean apa yang digunakan untuk menulis teks ke byte dan meneruskan pengkodean itu ke toString.
Stijn de Witt
10
Hanya klarifikasi pada codepage yang dirujuk di sini: di Java Anda dapat menggunakan Charset.defaultCharset () atau Charset.forName ("charset spesifik"); Apa yang berhasil untuk saya adalah: String baru (baos.toByteArray (), Charset.defaultCharset ());
Wallace Brown
7
@WallaceBrown menggunakan defaultCharsettidak lebih baik daripada mengabaikan charset sama sekali - Anda perlu mencari tahu apa itu sebelum Anda menggunakantoString
artbristol
4
StandardCharsets.UTF_8adalah a Charset, bukan a String. Apalagi parameternya dipanggil charsetName, bukan codepage.
OrangeDog
46

Saya suka perpustakaan Apache Commons IO. Lihatlah versi ByteArrayOutputStream , yang memiliki toString(String enc)metode juga toByteArray(). Menggunakan komponen yang ada dan tepercaya seperti proyek Commons memungkinkan kode Anda menjadi lebih kecil dan lebih mudah untuk diperluas dan digunakan kembali.

Joe Liversedge
sumber
10
Selamatkan diri Anda selama setahun dalam hidup Anda dan bacalah semua API umum sehingga saat Anda menghadapi masalah, Anda dapat mengeluarkan solusi yang sepenuhnya teruji dan milik komunitas.
Bob Herrmann
15
Hmm, saya pengguna Apache Commons yang rajin, tetapi dalam kasus ini saya gagal melihat mengapa Anda harus menggunakan ByteArrayOutputStream milik Commons IO daripada java.io.ByteArrayOutputStream milik JDK sendiri. Yang terakhir ini juga menyediakan metode toString (String charsetName) dan toByteArray (). Peduli menguraikan?
Jonik
1
Ya, karena konteks asli adalah cara yang lebih baik untuk melakukan streaming dan mengekstraksi konten, saya menyertakan contoh IO Commons karena menyertakan metode 'tulis (InputStream)' untuk mekanisme yang saat itu tidak ditentukan / dipertanyakan untuk mengisi OutputStream. Saya akan pergi dengan JDK juga.
Joe Liversedge
23

Ini bekerja dengan baik

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

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

kemudian untuk mencetak string atau mendapatkannya hanya referensi aliran "output" itu sendiri Sebagai contoh, untuk mencetak string ke konsol = >> System.out.println(output);

FYI: pemanggilan metode saya marshaller.marshal(Object,Outputstream)adalah untuk bekerja dengan XML. Itu tidak relevan dengan topik ini.

Ini sangat boros untuk penggunaan produk, ada terlalu banyak konversi dan agak longgar. Ini hanya kode untuk membuktikan kepada Anda bahwa sangat mungkin untuk membuat OuputStream khusus dan menghasilkan string. Tapi jalan Horcrux7 dan semuanya baik hanya dengan dua metode panggilan.

Dan dunia hidup di hari lain ....

MS
sumber
9
Hanya casting byte ke char hanya akan bekerja pada ascii. Gunakan ByteArrayOutputStream seperti Horcrux7
Dave Ray
2
Setuju dengan Dave Ray. Anda tidak dapat berasumsi bahwa byte Anda adalah karakter ASCII. Anda perlu menafsirkan byte menggunakan pengodean. Gunakan byteArrayOutputStream.toString ("UTF-8") atau String baru (byteArrayOutputStream.toByteArray (), "UTF-8").
Martin Dow
16

Inilah yang akhirnya saya lakukan:

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

Di mana os adalah ByteArrayOutputStream.

Adrian Mouat
sumber
2
@JavaJigs Saya mengklarifikasi ini di bagian bawah jawaban saya hampir 5 tahun yang lalu :)
Adrian Mouat
19
Pertimbangkan untuk mengganti "UTF-8"dengan StandardCharsets.UTF_8.
james.garriss