J'ai été surpris de constater aujourd'hui que je ne pouvais pas trouver de moyen simple d'écrire le contenu d'un InputStream
an OutputStream
en Java. De toute évidence, le code tampon d'octets n'est pas difficile à écrire, mais je soupçonne que je manque juste quelque chose qui me faciliterait la vie (et le code plus clair).
Donc, étant donné un InputStream
in
et un OutputStream
out
, existe-t-il un moyen plus simple d'écrire ce qui suit?
byte[] buffer = new byte[1024];
int len = in.read(buffer);
while (len != -1) {
out.write(buffer, 0, len);
len = in.read(buffer);
}
Réponses:
Java 9
Depuis Java 9,
InputStream
fournit une méthode appeléetransferTo
avec la signature suivante:Comme les documents états,
transferTo
seront:Donc, pour écrire le contenu d'un Java
InputStream
dans unOutputStream
, vous pouvez écrire:la source
Files.copy
autant que possible. Il est implémenté en code natif et peut donc être plus rapide.transferTo
ne doit être utilisé que si les deux flux ne sont pas FileInputStream / FileOutputStream.Files.copy
ne gère aucun flux d'entrée / sortie, mais il est spécialement conçu pour les flux de fichiers .Comme l'a mentionné WMR,
org.apache.commons.io.IOUtils
Apache a une méthode appeléecopy(InputStream,OutputStream)
qui fait exactement ce que vous recherchez.Vous avez donc:
... dans votre code.
Y a-t-il une raison que vous évitez
IOUtils
?la source
in
etout
doit être fermé à la fin du code dans un bloc enfinSi vous utilisez Java 7, Files (dans la bibliothèque standard) est la meilleure approche:
Edit: Bien sûr, c'est juste utile lorsque vous créez l'un des InputStream ou OutputStream à partir d'un fichier. Utilisez
file.toPath()
pour obtenir le chemin du fichier.Pour écrire dans un fichier existant (par exemple celui créé avec
File.createTempFile()
), vous devrez passer l'REPLACE_EXISTING
option de copie (sinon elleFileAlreadyExistsException
est levée):la source
Files
n'est PAS disponible dans Java 1.7 d' Android . J'ai été piqué par ceci: stackoverflow.com/questions/24869323/…Files.copy()
qui prend deux flux, et c'est ce que toutes les autresFiles.copy()
fonctions transmettent afin de faire le travail de copie. Cependant, il est privé (car il n'implique pas réellement de chemins ou de fichiers à ce stade) et ressemble exactement au code dans la propre question de l'OP (plus une déclaration de retour). Pas d'ouverture, pas de fermeture, juste une boucle de copie.Je pense que cela fonctionnera, mais assurez-vous de le tester ... "amélioration" mineure, mais cela pourrait être un peu coûteux en termes de lisibilité.
la source
while(len > 0)
place de!= -1
, car ce dernier peut également retourner 0 lors de l'utilisation de laread(byte b[], int off, int len)
méthode -met, qui lève une exception @out.write
InputStream
contrat de lire pour retourner 0 autant de fois. Et selon leOutputStream
contrat, la méthode d'écriture doit accepter une longueur de 0 et ne doit lever une exception que lorsqu'ellelen
est négative.while
unefor
et de mettre l' une des variables pour la section de Init: par exemplefor (int n ; (n = in.read(buf)) != -1 ;) out.write(buf, 0, n);
. =)read()
ne peut retourner zéro que si vous avez fourni une longueur de zéro, ce qui serait une erreur de programmation et une condition stupide pour boucler indéfiniment. Etwrite()
ne lève pas d'exception si vous fournissez une longueur nulle.Utilisation de la goyave
ByteStreams.copy()
:la source
Files.copy
autant que possible. À utiliserByteStreams.copy
uniquement si les deux flux ne sont pas FileInputStream / FileOutputStream.Fonction simple
Si vous n'en avez besoin que pour écrire un
InputStream
dans un,File
vous pouvez utiliser cette fonction simple:la source
close()
appels enfinally
bloc?Le
JDK
utilise le même code, il semble donc qu'il n'y a pas de moyen "plus facile" sans bibliothèques tierces maladroites (qui ne font probablement rien de différent de toute façon). Ce qui suit est directement copié dejava.nio.file.Files.java
:la source
PipedInputStream
etPipedOutputStream
ne doit être utilisé que lorsque vous avez plusieurs threads, comme indiqué par Javadoc .Notez également que les flux d'entrée et les flux de sortie n'encapsulent aucune interruption de thread avec
IOException
s ... Donc, vous devriez envisager d'incorporer une politique d'interruption à votre code:Ce serait un ajout utile si vous prévoyez d'utiliser cette API pour copier de gros volumes de données ou des données de flux qui restent bloqués pendant une durée intolérable.
la source
Pour ceux qui utilisent Spring Framework, il existe une classe StreamUtils utile :
Ce qui précède ne ferme pas les flux. Si vous souhaitez que les flux soient fermés après la copie, utilisez plutôt la classe FileCopyUtils :
la source
Il n'y a aucun moyen de le faire beaucoup plus facilement avec les méthodes JDK, mais comme Apocalisp l'a déjà noté, vous n'êtes pas le seul à avoir cette idée: vous pouvez utiliser des IOUtils de Jakarta Commons IO , il a aussi beaucoup d'autres choses utiles, que l'OMI devrait en fait faire partie du JDK ...
la source
Utilisant Java7 et try-with-resources , est livré avec une version simplifiée et lisible.
la source
Voici comment je fais avec le plus simple pour la boucle.
la source
Utilisez la classe Util de Commons Net:
la source
Un extrait de mon humble avis plus minimal (qui étend également plus étroitement la variable de longueur):
En remarque, je ne comprends pas pourquoi plus de gens n'utilisent pas de
for
boucle, optant plutôt pour unwhile
avec une expression assign-and-test qui est considérée par certains comme un style "pauvre".la source
for(int n = 0; (n = in.read(buffer)) > 0;) { out.write(buffer, 0, n); }
Ceci est mon meilleur coup !!
Et ne l'utilisez pas
inputStream.transferTo(...)
car il est trop générique. Les performances de votre code seront meilleures si vous contrôlez votre mémoire tampon.Je l'utilise avec cette méthode (évolutive) quand je connais à l'avance la taille du flux.
la source
Je pense qu'il vaut mieux utiliser un grand tampon, car la plupart des fichiers sont supérieurs à 1024 octets. Il est également recommandé de vérifier que le nombre d'octets de lecture est positif.
la source
J'utilise
BufferedInputStream
etBufferedOutputStream
pour supprimer la sémantique de mise en mémoire tampon du codela source
PipedInputStream et PipedOutputStream peuvent être d'une certaine utilité, car vous pouvez vous connecter l'un à l'autre.
la source
Un autre candidat possible sont les utilitaires d'E / S Guava:
http://code.google.com/p/guava-libraries/wiki/IOExplained
J'ai pensé les utiliser car Guava est déjà extrêmement utile dans mon projet, plutôt que d'ajouter une autre bibliothèque pour une fonction.
la source
copy
ettoByteArray
méthodes docs.guava-libraries.googlecode.com/git-history/release/javadoc/... (goyave appels flux d' entrée / sortie en tant que « flux d'octets » et les lecteurs / auteurs comme « flux char »)Pas très lisible, mais efficace, sans dépendances et fonctionne avec n'importe quelle version java
la source
!= -1
ou> 0
? Ces prédicats ne sont pas tout à fait les mêmes.la source
Essayez Cactoos :
Plus de détails ici: http://www.yegor256.com/2017/06/22/object-oriented-input-output-in-cactoos.html
la source
vous pouvez utiliser cette méthode
la source
catch(Exception ex){}
- c'est top