Si vous avez un java.io.InputStream
objet, comment devez-vous le traiter et en produire un String
?
Supposons que j'aie un InputStream
qui contient des données texte et que je souhaite le convertir enString
un fichier en un fichier, par exemple, je peux l'écrire dans un fichier journal.
Quelle est la façon la plus simple de prendre le InputStream
et de le convertir en un String
?
public String convertStreamToString(InputStream is) {
// ???
}
ByteArrayOutputStream outputBytes = new ByteArrayOutputStream();
for(byte[] b = new byte[512]; 0 < inputStream.read(b); outputBytes.write(b));
return new String(outputBytes.toByteArray(), StandardCharsets.UTF_8);
String s = Files.readString(Path.of("SomeFile.txt"));
ce qui est aussi bon qu'un langage peut obtenir, qui ne supportera jamais de telles conversions de type magique comme celle que vous avez décrite.Réponses:
Une bonne façon de le faire est d'utiliser les communs Apache
IOUtils
pour copier leInputStream
dans unStringWriter
... quelque chose commeou même
Alternativement, vous pouvez utiliser
ByteArrayOutputStream
si vous ne souhaitez pas mélanger vos flux et écrivainsla source
Résumez les autres réponses. J'ai trouvé 11 façons principales de le faire (voir ci-dessous). Et j'ai écrit quelques tests de performances (voir les résultats ci-dessous):
Façons de convertir un InputStream en une chaîne:
Utilisation
IOUtils.toString
(Apache Utils)Utilisation de
CharStreams
(goyave)Utilisation de
Scanner
(JDK)Utilisation de l' API Stream (Java 8). Avertissement : cette solution convertit différents sauts de ligne (comme
\r\n
) en\n
.Utilisation de l' API Stream parallèle (Java 8). Avertissement : cette solution convertit différents sauts de ligne (comme
\r\n
) en\n
.Utilisation de
InputStreamReader
etStringBuilder
(JDK)Utilisation de
StringWriter
etIOUtils.copy
(Apache Commons)Utilisation de
ByteArrayOutputStream
etinputStream.read
(JDK)Utilisation de
BufferedReader
(JDK). Avertissement: cette solution convertit différents sauts de ligne (comme\n\r
) enline.separator
propriété système (par exemple, dans Windows en "\ r \ n").Utilisation de
BufferedInputStream
etByteArrayOutputStream
(JDK)Utilisation de
inputStream.read()
etStringBuilder
(JDK). Avertissement : cette solution a des problèmes avec Unicode, par exemple avec du texte russe (ne fonctionne correctement qu'avec du texte non Unicode)Attention :
Les solutions 4, 5 et 9 convertissent différents sauts de ligne en un seul.
La solution 11 ne peut pas fonctionner correctement avec du texte Unicode
Des tests de performance
Tests de performances pour les petits
String
(longueur = 175), URL dans github (mode = temps moyen, système = Linux, le score de 1 343 est le meilleur):Tests de performances pour big
String
(longueur = 50100), url dans github (mode = temps moyen, système = Linux, le score 200 715 est le meilleur):Graphiques (tests de performances en fonction de la longueur du flux d'entrée dans le système Windows 7)
Test de performance (durée moyenne) en fonction de la longueur du flux d'entrée dans le système Windows 7:
la source
\r\n
) en\n
lesquels peuvent être indésirables dans certains cas. Il serait également intéressant de voir la mémoire supplémentaire requise ou au moins la pression d'allocation (au moins vous pouvez exécuter JMH avec-prof gc
). Pour le post vraiment cool, ce serait génial de voir les graphiques (en fonction de la longueur de chaîne dans la même taille d'entrée et en fonction de la taille d'entrée dans la même longueur de chaîne).reset()
dans l'exemple 11?Voici un moyen d'utiliser uniquement la bibliothèque Java standard (notez que le flux n'est pas fermé, votre kilométrage peut varier).
J'ai appris cette astuce dans l'article "Astuces du scanner stupide" . La raison pour laquelle cela fonctionne est que le scanner parcourt les jetons dans le flux, et dans ce cas, nous séparons les jetons en utilisant le "début de la limite d'entrée" (\ A), nous donnant ainsi un seul jeton pour tout le contenu du flux.
Remarque, si vous devez être précis sur l'encodage du flux d'entrée, vous pouvez fournir le deuxième argument au
Scanner
constructeur qui indique le jeu de caractères à utiliser (par exemple "UTF-8").La pointe du chapeau va également à Jacob , qui m'a un jour indiqué ledit article.
la source
if (is == null) return "";
dès le début de la méthode; Je crois que cette réponse doit être mise à jour pour mieux gérer les entrées nulles.try(java.util.Scanner s = new java.util.Scanner(is)) { return s.useDelimiter("\\A").hasNext() ? s.next() : ""; }
Apache Commons permet:
Bien sûr, vous pouvez choisir d'autres encodages de caractères en plus de l'UTF-8.
Voir aussi: ( documentation )
la source
En tenant compte du fichier, il faut d'abord obtenir une
java.io.Reader
instance. Cela peut ensuite être lu et ajouté à unStringBuilder
(nous n'avons pas besoinStringBuffer
si nous n'y accédons pas dans plusieurs threads, etStringBuilder
c'est plus rapide). L'astuce ici est que nous travaillons en blocs, et en tant que tels, nous n'avons pas besoin d'autres flux de mise en mémoire tampon. La taille de bloc est paramétrée pour l'optimisation des performances d'exécution.la source
In our product, I even replaced
devrait être «nous avons même remplacé».Utilisation:
la source
readLine
lu caractère par caractère pour rechercher EOL. De plus, s'il n'y a pas de saut de ligne dans le flux, cela n'a pas vraiment de sens.Si vous utilisez Google-Collections / Guava, vous pouvez procéder comme suit:
Notez que le deuxième paramètre (c'est-à-dire Charsets.UTF_8) pour le
InputStreamReader
n'est pas nécessaire, mais c'est généralement une bonne idée de spécifier l'encodage si vous le connaissez (ce que vous devriez!)la source
Il s'agit de la meilleure solution Java pure qui s'adapte parfaitement à Android et à toute autre machine virtuelle Java.
Cette solution fonctionne incroyablement bien ... elle est simple, rapide et fonctionne tout de même sur les petits et les grands flux !! (voir référence ci-dessus .. n ° 8 )
la source
2*n
, où n est la taille du flux, selon leByteArrayInputStream
système de croissance automatique.Pour être complet, voici la solution Java 9 :
Le
readAllBytes
est actuellement dans la base de code principale de JDK 9, il devrait donc apparaître dans la version. Vous pouvez l'essayer dès maintenant en utilisant les versions d'instantanés JDK 9 .la source
byte[] buf = new byte[DEFAULT_BUFFER_SIZE];
oùMAX_BUFFER_SIZE = Integer.MAX_VALUE - 8;
qui donneMAX_BUFFER_SIZE = 2147483639
. Google dit que c'est environ 2,147 Go.InputStream
, pas surPath
. LeInputStream
peut être créé à partir de nombreuses sources différentes, pas seulement de fichiers.byte[]
implémentation si tous les caractères sont dans les 256 premiers points de code. Cela signifie que la nouvelle chaîne (octet [], "ISO-Latin-1") sera une simple copie de tableau.Utilisation:
la source
BufferedInputStream
. Les lectures sous-jacentes sont de 8192 octets à la fois.BufferedInputStream
et la lecture dans un tampon de tableau d'octets au lieu d'un octet à la fois. Exemple: 200 ms contre 60 ms lors de la lecture d'un fichier de 4,56 Mio.buf.toString()
.Voici la solution la plus élégante, pure Java (sans bibliothèque) que j'ai trouvée après quelques expérimentations:
la source
InputStream
doit être fermé par l'appelant.readLine
? si vous n'utilisez pas les lignes en soi, à quoi cela sert-il (sauf d'être très lent?)J'ai fait un benchmark sur 14 réponses distinctes ici (désolé de ne pas fournir de crédits mais il y a trop de doublons).
Le résultat est très surprenant. Il s'avère que Apache IOUtils est la solution la plus lente et
ByteArrayOutputStream
la plus rapide:Voici donc d'abord la meilleure méthode:
Résultats de référence, de 20 Mo d'octets aléatoires en 20 cycles
Temps en millisecondes
Code source de référence
la source
J'utiliserais quelques astuces Java 8.
Essentiellement les mêmes que certaines autres réponses, sauf plus succinctes.
la source
return null
jamais appelé? Soit lebr.lines...
retour, soit une exception est levée.parallel()
sur le flux?\r\n
finirait par être converti en\n
...System.lineSeparator()
pour utiliser la fin de ligne dépendante de la plate-forme appropriée.J'ai fait des tests de chronométrage car le temps compte, toujours.
J'ai essayé d'obtenir la réponse dans une chaîne de 3 manières différentes. (montré ci-dessous)
J'ai laissé de côté les blocs try / catch pour la lisibilité.
Pour donner le contexte, voici le code précédent pour les 3 approches:
1)
2)
3)
Ainsi, après avoir exécuté 500 tests sur chaque approche avec les mêmes données de demande / réponse, voici les chiffres. Encore une fois, ce sont mes conclusions et vos conclusions ne sont peut-être pas exactement les mêmes, mais j'ai écrit ceci pour donner une indication aux autres des différences d'efficacité de ces approches.
Classements:
Approche n ° 1
Approche n ° 3 - 2,6% plus lent que n ° 1
Approche n ° 2 - 4,3% plus lent que n ° 1
Chacune de ces approches est une solution appropriée pour récupérer une réponse et en créer une chaîne.
la source
Solution Java pure utilisant Stream s, fonctionne depuis Java 8.
Comme mentionné par Christoffer Hammarström ci - dessous autre réponse , il est plus sûr de spécifier explicitement le jeu de caractères . C'est-à-dire que le constructeur InputStreamReader peut être modifié comme suit:
la source
Charset.forName("UTF-8")
, utilisezStandardCharsets.UTF_8
(fromjava.nio.charset
).Voici la réponse de Sampath plus ou moins, nettoyée un peu et représentée comme une fonction:
la source
Si vous vous sentiez aventureux, vous pourriez mélanger Scala et Java et vous retrouver avec ceci:
Le mélange de code et de bibliothèques Java et Scala a ses avantages.
Voir la description complète ici: façon idiomatique de convertir un InputStream en une chaîne dans Scala
la source
Source.fromInputStream(...).mkString
Si vous ne pouvez pas utiliser Commons IO (FileUtils / IOUtils / CopyUtils), voici un exemple utilisant un BufferedReader pour lire le fichier ligne par ligne:
Ou si vous voulez une vitesse brute, je proposerais une variation de ce que Paul de Vrieze a suggéré (ce qui évite d'utiliser un StringWriter (qui utilise un StringBuffer en interne):
la source
Celui-ci est sympa car:
Comment faire?
Pour JDK 9
la source
catch (Throwable)
ne devrait pas vraiment être vide s'il s'agit d'un code de production.Ceci est une réponse adaptée du
org.apache.commons.io.IOUtils
code source , pour ceux qui veulent avoir l'implémentation d'apache mais ne veulent pas la bibliothèque entière.la source
Assurez-vous de fermer les flux à la fin si vous utilisez des lecteurs de flux
EDIT: Sur JDK 7+, vous pouvez utiliser la construction try-with-resources.
la source
iStream
devrait plutôt être fermé par l'appelant parce que l'appelant a crééiStream
. En outre, la fermeture des flux doit être effectuée dans unfinally
bloc, ou mieux dans une instruction Java 7 try-with-resources. Dans votre code, lorsquereadLine()
jetteIOException
, oubuilder.append()
jetteOutOfMemoryError
, les flux resteraient ouverts.Un autre, pour tous les utilisateurs de Spring:
Les méthodes utilitaires dans
org.springframework.util.StreamUtils
sont similaires à celles deFileCopyUtils
, mais elles laissent le flux ouvert une fois terminé.la source
Utilisez le java.io.InputStream.transferTo (OutputStream) pris en charge dans Java 9 et le ByteArrayOutputStream.toString (String) qui prend le nom du jeu de caractères:
la source
Voici la méthode complète pour convertir
InputStream
enString
sans utiliser de bibliothèque tierce. UtiliserStringBuilder
pour un environnement à thread unique sinon utiliserStringBuffer
.la source
in = new InputStreamReader(inputStream)
et(char)in.read()
.Voici comment le faire en utilisant uniquement le JDK en utilisant des tampons de tableau d'octets. C'est en fait ainsi que fonctionnent les
IOUtils.copy()
méthodes communes-io . Vous pouvez remplacerbyte[]
parchar[]
si vous copiez à partir d'unReader
au lieu d'unInputStream
.la source
Les utilisateurs de Kotlin font simplement:
tandis que
est la méthode d'extension intégrée de la bibliothèque standard de Kotlin.
la source
is.bufferedReader().use { it.readText() }
.Le moyen le plus simple dans JDK consiste à utiliser les extraits de code suivants.
la source
Voici ma solution basée sur Java 8 , qui utilise la nouvelle API Stream pour collecter toutes les lignes d'un
InputStream
:la source
En termes de
reduce
, etconcat
il peut être exprimé en Java 8 comme:la source
StringBuilder
pourrait être plus efficace. Je vais vérifier, mais mon but était de montrer une approche plus fonctionnelle avec immuableString
.Réponse JDK 7/8 qui ferme le flux et lève toujours une exception IOException:
la source