Bagaimana cara mengonversi Pembaca ke InputStream dan Penulis menjadi OutputStream?

89

Apakah ada cara mudah untuk menghindari masalah pengkodean teks?

Andrei Savu
sumber

Jawaban:

46

Anda tidak dapat benar-benar menghindari berurusan dengan masalah pengkodean teks, tetapi ada solusi yang ada di Apache Commons:

Anda hanya perlu memilih pengkodean pilihan Anda.

Peter
sumber
7
FYI: kode ReaderInputStream memiliki bug dalam cara membaca byte (tidak akan bekerja untuk semua pengkodean). Bukti: illegalargumentexception.blogspot.com/2009/05/… Ada bug terbuka: issues.apache.org/bugzilla/show_bug.cgi?id=40455
McDowell
1
Anda dapat menemukan kelas-kelas di perpustakaan commons-io Apache: commons.apache.org/proper/commons-io
AlikElzin-kilaka
@McDowell, bug yang Anda sebutkan ada di implementasi Apache Ant, bukan di commons-io's, jadi tidak relevan dengan jawaban ini.
Roman
94

Jika Anda memulai dengan String, Anda juga dapat melakukan hal berikut:

new ByteArrayInputStream(inputString.getBytes("UTF-8"))
Ritesh Tendulkar
sumber
7
ReaderInputStreamImplementasi yang baik akan membutuhkan lebih sedikit memori - seharusnya tidak perlu menyimpan semua byte dalam array sekaligus.
Piotr Findeisen
3
Saya suka solusi ini karena berfungsi ketika Anda perlu kode uji unit yang menerima input pada (misalnya) input standar.
Kedar Mhaswade
43

Nah, Pembaca berurusan dengan karakter dan InputStream berurusan dengan byte. Pengkodean menentukan bagaimana Anda ingin merepresentasikan karakter Anda sebagai byte, jadi Anda tidak bisa mengabaikan masalah ini. Adapun untuk menghindari masalah, pendapat saya adalah: pilih satu rangkaian karakter (misalnya "UTF-8") dan pertahankan.

Mengenai bagaimana sebenarnya melakukannya, seperti yang telah ditunjukkan, " nama yang jelas untuk kelas ini adalah ReaderInputStream dan WriterOutputStream . " Anehnya, " ini tidak termasuk dalam pustaka Java " meskipun kelas 'berlawanan', InputStreamReader dan OutputStreamWriter adalah termasuk.

Jadi, banyak orang yang membuat implementasinya sendiri, termasuk Apache Commons IO . Bergantung pada masalah lisensi, Anda mungkin dapat menyertakan pustaka commons-io dalam proyek Anda, atau bahkan menyalin sebagian dari kode sumber (yang dapat diunduh di sini ).

Seperti yang Anda lihat, dokumentasi kedua kelas menyatakan bahwa "semua encoding charset yang didukung oleh JRE ditangani dengan benar".

NB Sebuah komentar di salah satu jawaban lain di sini menyebutkan bug ini . Tapi itu memengaruhi kelas Apache Ant ReaderInputStream (di sini ), bukan kelas Apache Commons IO ReaderInputStream.

Peter Ford
sumber
19

Perhatikan juga bahwa, jika Anda memulai dengan String, Anda dapat melewati pembuatan StringReader dan membuat InputStream dalam satu langkah menggunakan org.apache.commons.io.IOUtils dari Commons IO seperti:

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

Tentu Anda masih perlu memikirkan tentang pengkodean teks, tetapi setidaknya konversi terjadi dalam satu langkah.

Phil Harvey
sumber
4
Metode ini pada dasarnya new ByteArrayInputStream(report.toString().getBytes("utf-8")), yang melibatkan alokasi dua salinan tambahan dari laporan dalam memori. Jika laporannya besar, itu buruk. Lihat jawabanku.
Oliv
8

Menggunakan:

new CharSequenceInputStream(html, StandardCharsets.UTF_8);

Cara ini tidak memerlukan konversi dimuka ke Stringdan kemudian ke byte[], yang mengalokasikan lebih banyak memori heap, jika laporannya besar. Ini mengubah menjadi byte dengan cepat saat aliran dibaca, langsung dari StringBuffer.

Ini menggunakan CharSequenceInputStream dari proyek Apache Commons IO.

Oliv
sumber
5

Nama yang jelas untuk kelas ini adalah ReaderInputStream dan WriterOutputStream. Sayangnya ini tidak termasuk dalam perpustakaan Java. Bagaimanapun, google adalah temanmu.

Saya tidak yakin bahwa ini akan mengatasi semua masalah pengkodean teks, yang merupakan mimpi buruk.

Ada RFE, tapi Ditutup, tidak akan diperbaiki.

Tom Hawtin - tackline
sumber
1
bugs.openjdk.java.net/browse/JDK-4103785 berisi komentar "kami memiliki API publik untuk pengkodean kumpulan karakter ... tidak ada alasan kuat untuk menambahkan kelas-kelas ini" - jadi bagaimana seseorang melakukannya di Java 7, tanpa tambahan perpustakaan, dua belas tahun ke depan?
Piotr Findeisen
5

Anda tidak dapat menghindari masalah pengkodean teks, tetapi Apache commons-io memilikinya

Perhatikan bahwa ini adalah perpustakaan yang dirujuk dalam jawaban Peter di koders.com, cukup tautan ke perpustakaan alih-alih kode sumber.

dfrankow
sumber
4

Apakah Anda mencoba menulis konten a Readerke an OutputStream? Jika demikian, Anda akan memiliki waktu lebih mudah membungkus OutputStreamdalam OutputStreamWriterdan menulis chars dari Readerke Writer, alih-alih mencoba untuk mengkonversi pembaca ke 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
sumber
1

Peringatan saat menggunakan WriterOutputStream - tidak selalu menangani penulisan data biner ke file dengan benar / sama dengan aliran keluaran biasa. Saya memiliki masalah dengan hal ini yang memerlukan beberapa saat untuk saya lacak.

Jika Anda bisa, saya sarankan untuk menggunakan aliran keluaran sebagai basis Anda, dan jika Anda perlu menulis string, gunakan pembungkus OUtputStreamWriter di sekitar aliran untuk melakukannya. Jauh lebih dapat diandalkan untuk mengonversi teks menjadi byte daripada sebaliknya, yang mungkin menjadi alasan WriterOutputStream bukan bagian dari pustaka Java standar

romeara
sumber
-1

Untuk Membaca string dalam aliran hanya menggunakan apa yang disediakan java.

InputStream s = new BufferedInputStream( new ReaderInputStream( new StringReader("a string")));
Aaron
sumber
6
ReaderInputStream ada di Apache Commons IO.
Akan Beason