Comment convertir un Reader en InputStream et un Writer en OutputStream?

87

Existe-t-il un moyen simple d'éviter de traiter les problèmes de codage de texte?

Andrei Savu
la source

Réponses:

45

Vous ne pouvez pas vraiment éviter de traiter les problèmes d'encodage de texte, mais il existe des solutions existantes dans Apache Commons:

Il vous suffit de choisir l'encodage de votre choix.

Peter
la source
7
Pour info: le code ReaderInputStream a un bug dans la façon dont il lit les octets (cela ne fonctionnera pas pour tous les encodages). Preuve : legalargumentexception.blogspot.com/2009/05 / ... Il y a un bug ouvert: issues.apache.org/bugzilla/show_bug.cgi?id=40455
McDowell
1
Vous pouvez trouver les classes dans la bibliothèque commons-io Apache: commons.apache.org/proper/commons-io
AlikElzin-Kilaka
@McDowell, le bogue que vous avez mentionné se trouve dans l'implémentation d'Apache Ant, pas dans celle de commons-io, donc il n'est pas pertinent pour cette réponse.
Roman
94

Si vous commencez avec une chaîne, vous pouvez également effectuer les opérations suivantes:

new ByteArrayInputStream(inputString.getBytes("UTF-8"))
Ritesh Tendulkar
la source
7
Une bonne ReaderInputStreamimplémentation nécessiterait moins de mémoire - il ne devrait pas être nécessaire de stocker tous les octets d'un tableau à la fois.
Piotr Findeisen
3
J'aime cette solution car elle fonctionne lorsque vous avez besoin d'un code de test unitaire qui accepte l'entrée sur (par exemple) l'entrée standard.
Kedar Mhaswade
42

Eh bien, un Reader traite des caractères et un InputStream traite des octets. Le codage spécifie comment vous souhaitez représenter vos caractères sous forme d'octets, vous ne pouvez donc pas vraiment ignorer le problème. Quant à éviter les problèmes, mon avis est le suivant: choisissez un jeu de caractères (par exemple "UTF-8") et respectez-le.

En ce qui concerne la manière de le faire, comme cela a été souligné, « les noms évidents de ces classes sont ReaderInputStream et WriterOutputStream . » Étonnamment, « ils ne sont pas inclus dans la bibliothèque Java » même si les classes «opposées», InputStreamReader et OutputStreamWriter sont inclus.

Ainsi, beaucoup de gens ont mis au point leurs propres implémentations, y compris Apache Commons IO . En fonction des problèmes de licence, vous pourrez probablement inclure la bibliothèque commons-io dans votre projet, ou même copier une partie du code source (qui est téléchargeable ici ).

Comme vous pouvez le voir, la documentation des deux classes indique que «tous les encodages de charset pris en charge par le JRE sont gérés correctement».

NB Un commentaire sur l'une des autres réponses ici mentionne ce bug . Mais cela affecte la classe Apache Ant ReaderInputStream ( ici ), pas la classe Apache Commons IO ReaderInputStream.

Peter Ford
la source
19

Notez également que, si vous commencez avec une chaîne, vous pouvez ignorer la création d'un StringReader et créer un InputStream en une seule étape à l'aide de org.apache.commons.io.IOUtils de Commons IO comme ceci:

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

Bien sûr, vous devez toujours penser à l'encodage du texte, mais au moins la conversion se fait en une seule étape.

Phil Harvey
la source
4
Cette méthode fonctionne essentiellement new ByteArrayInputStream(report.toString().getBytes("utf-8")), ce qui implique l'allocation de deux copies supplémentaires du rapport en mémoire. Si le rapport est volumineux, il est mauvais. Voyez ma réponse.
Oliv
8

Utilisation:

new CharSequenceInputStream(html, StandardCharsets.UTF_8);

Cette méthode ne nécessite pas de conversion initiale vers String, puis vers byte[], ce qui alloue beaucoup plus de mémoire de tas, au cas où le rapport serait volumineux. Il se convertit en octets à la volée lorsque le flux est lu, directement à partir du StringBuffer.

Il utilise CharSequenceInputStream du projet Apache Commons IO.

Oliv
la source
5

Les noms évidents de ces classes sont ReaderInputStream et WriterOutputStream. Malheureusement, ceux-ci ne sont pas inclus dans la bibliothèque Java. Cependant, Google est votre ami.

Je ne suis pas sûr que cela va contourner tous les problèmes d'encodage de texte, qui sont cauchemardesques.

Il y a un RFE, mais il est fermé, ne résoudra pas.

Tom Hawtin - Tacle
la source
1
bugs.openjdk.java.net/browse/JDK-4103785 contient le commentaire "nous avons une API publique pour le codage de jeux de caractères ... aucune raison impérieuse d'ajouter ces classes" - alors comment faire cela dans Java 7, sans supplément bibliothèques, douze ans plus tard?
Piotr Findeisen
5

Vous ne pouvez pas éviter les problèmes d'encodage de texte, mais Apache commons-io a

Notez que ce sont les bibliothèques auxquelles il est fait référence dans la réponse de Peter sur koders.com, juste des liens vers la bibliothèque au lieu du code source.

dfrankow
la source
4

Essayez-vous d'écrire le contenu d'un Readerdans un OutputStream? Si tel est le cas, vous aurez plus de facilité à encapsuler le OutputStreamdans un OutputStreamWriteret à écrire le chars du Readervers le Writer, au lieu d'essayer de convertir le lecteur en 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
Sam Barnum
la source
1

Un avertissement lors de l'utilisation de WriterOutputStream - il ne gère pas toujours l'écriture de données binaires dans un fichier correctement / de la même manière qu'un flux de sortie normal. J'ai eu un problème avec cela qui m'a pris un certain temps à retrouver.

Si vous le pouvez, je vous recommande d'utiliser un flux de sortie comme base, et si vous avez besoin d'écrire des chaînes, utilisez un wrapper OUtputStreamWriter autour du flux pour le faire. Il est beaucoup plus fiable de convertir du texte en octets que l'inverse, ce qui explique probablement pourquoi WriterOutputStream ne fait pas partie de la bibliothèque Java standard

romeara
la source
-1

Pour lire une chaîne dans un flux en utilisant exactement ce que java fournit.

InputStream s = new BufferedInputStream( new ReaderInputStream( new StringReader("a string")));
Aaron
la source
6
ReaderInputStream est dans Apache Commons IO.
Will Beason