Come convertire un lettore in InputStream e uno scrittore in OutputStream?


89

C'è un modo semplice per evitare di affrontare i problemi di codifica del testo?

Risposte:


46

Non puoi davvero evitare di affrontare i problemi di codifica del testo, ma ci sono soluzioni esistenti in Apache Commons:

Devi solo scegliere la codifica che preferisci.


7
FYI: il codice ReaderInputStream ha un bug nel modo in cui legge i byte (non funzionerà per tutte le codifiche). Prova: illegaleargumentexception.blogspot.com/2009/05/… C'è un bug aperto: issues.apache.org/bugzilla/show_bug.cgi?id=40455
McDowell

1
Puoi trovare le classi nella libreria commons-io di Apache: commons.apache.org/proper/commons-io
AlikElzin-kilaka

@ McDowell, il bug che hai citato è nell'implementazione di Apache Ant, non in commons-io, quindi non è rilevante per questa risposta.
Roman

94

Se stai iniziando con una stringa puoi anche fare quanto segue:

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

7
Una buona ReaderInputStreamimplementazione richiederebbe meno memoria: non dovrebbe essere necessario memorizzare tutti i byte in un array contemporaneamente.
Piotr Findeisen

3
Mi piace questa soluzione perché funziona quando è necessario un codice di test unitario che accetta input su (ad esempio) input standard.
Kedar Mhaswade,

43

Ebbene, un Reader si occupa di caratteri e un InputStream si occupa di byte. La codifica specifica come desideri rappresentare i tuoi caratteri come byte, quindi non puoi davvero ignorare il problema. Per quanto riguarda evitare problemi, la mia opinione è: scegli un set di caratteri (ad esempio "UTF-8") e mantienilo.

Per quanto riguarda come fare in realtà, come è stato sottolineato, " i nomi ovvie per queste classi sono ReaderInputStream e WriterOutputStream . " Sorprendentemente, " questi non sono inclusi nella libreria Java ", anche se le classi 'opposti', InputStreamReader e OutputStreamWriter sono incluso.

Quindi, molte persone hanno escogitato le proprie implementazioni, incluso Apache Commons IO . A seconda dei problemi di licenza, probabilmente sarai in grado di includere la libreria commons-io nel tuo progetto, o anche copiare una parte del codice sorgente (che è scaricabile qui ).

Come puoi vedere, la documentazione di entrambe le classi afferma che "tutte le codifiche dei set di caratteri supportate da JRE sono gestite correttamente".

NB Un commento su una delle altre risposte qui menziona questo bug . Ma ciò influisce sulla classe Apache Ant ReaderInputStream ( qui ), non sulla classe Apache Commons IO ReaderInputStream.


19

Si noti inoltre che, se si inizia con una stringa, è possibile saltare la creazione di un StringReader e creare un InputStream in un unico passaggio utilizzando org.apache.commons.io.IOUtils da Commons IO in questo modo:

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

Ovviamente devi ancora pensare alla codifica del testo, ma almeno la conversione avviene in un unico passaggio.


4
Questo metodo funziona fondamentalmente new ByteArrayInputStream(report.toString().getBytes("utf-8")), il che implica l'allocazione di due copie aggiuntive del report in memoria. Se il rapporto è grande, è cattivo. Vedi la mia risposta.
Oliv

8

Uso:

new CharSequenceInputStream(html, StandardCharsets.UTF_8);

In questo modo non è necessaria una conversione anticipata in Stringe poi inbyte[] , che alloca molta più memoria heap, nel caso in cui il report sia di grandi dimensioni. Si converte in byte al volo durante la lettura del flusso, direttamente da StringBuffer.

Utilizza CharSequenceInputStream dal progetto Apache Commons IO.



5

I nomi ovvi per queste classi sono ReaderInputStream e WriterOutputStream. Purtroppo questi non sono inclusi nella libreria Java. Tuttavia, Google è tuo amico.

Non sono sicuro che risolverà tutti i problemi di codifica del testo, che sono da incubo.

C'è un RFE, ma è chiuso, non verrà risolto.


1
bugs.openjdk.java.net/browse/JDK-4103785 contiene il commento "abbiamo un'API pubblica per la codifica del set di caratteri ... nessun motivo valido per aggiungere queste classi" - quindi come si fa in Java 7, senza ulteriori biblioteche, dodici anni dopo?
Piotr Findeisen


4

Stai cercando di scrivere il contenuto di a Readerin un OutputStream? In tal caso, sarà più facile avvolgere il OutputStreamin un OutputStreamWritere scrivere la chars da Readera Writer, invece di provare a convertire il lettore in un 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

Un avviso quando si utilizza WriterOutputStream: non gestisce sempre la scrittura di dati binari in un file correttamente / lo stesso di un normale flusso di output. Ho avuto un problema con questo che mi ci è voluto del tempo per rintracciarlo.

Se puoi, ti consiglio di utilizzare un flusso di output come base e, se devi scrivere stringhe, utilizza un wrapper OUtputStreamWriter attorno al flusso per farlo. È molto più affidabile convertire il testo in byte rispetto al contrario, motivo per cui WriterOutputStream non fa parte della libreria Java standard



-1

Per leggere una stringa in un flusso utilizzando solo ciò che fornisce Java.

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

6
ReaderInputStream è in Apache Commons IO.
Will Beason
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.