Moyen facile d'écrire du contenu d'une application Java InputStream à un OutputStream
J'ai été surpris de constater aujourd'hui que je ne pouvais pas trouver quelque moyen simple d'écrire le contenu d'un InputStream
à un OutputStream
en Java. Évidemment, le tampon d'octets de code n'est pas difficile à écrire, mais je pense que je suis juste en manque de quelque chose qui allait me rendre la vie plus facile (et le code plus clair).
Donc, étant donné un InputStream
in
et un OutputStream
out
, est-il un moyen plus simple d'écrire la suite?
byte[] buffer = new byte[1024];
int len = in.read(buffer);
while (len != -1) {
out.write(buffer, 0, len);
len = in.read(buffer);
}
- Vous avez mentionné dans un commentaire que c'est pour une application mobile. Il est natif d'Android? Si oui, laissez-moi savoir et je vais poster une autre réponse (il peut être fait en une seule ligne de code sur Android).
Vous devez vous connecter pour publier un commentaire.
Java 9
Depuis Java 9,
InputStream
fournit une méthode appeléetransferTo
avec la signature suivante:Comme le la documentation unis,
transferTo
sera:Donc dans l'ordre pour écrire du contenu d'une application Java
InputStream
à unOutputStream
, vous pouvez écrire:Files.copy
autant que possible. Il est mis en œuvre dans le code natif et peut donc être plus rapide.transferTo
devrait être utilisé seulement si les deux flux ne sont pas FileInputStream/FileOutputStream.Comme WMR mentionné,
org.apache.commons.io.IOUtils
de Apache a une méthode appeléecopier(InputStream,OutputStream)
qui fait exactement ce que vous cherchez.Donc, vous avez:
...dans votre code.
Est-il une raison pour laquelle vous êtes en évitant
IOUtils
?in
etout
doit être fermé à la fin du code dans un bloc finally.jar
, ce qui entraîne qu'une augmentation modeste dans le fichier jar tailleSi vous êtes à l'aide de Java 7, Fichiers (dans la bibliothèque standard) est la meilleure approche:
Edit: bien sûr, c'est juste utile lorsque vous créez un de InputStream ou OutputStream à partir d'un fichier. Utilisation
file.toPath()
pour obtenir de chemin d'accès de fichier.Pour écrire dans un fichier existant (par exemple, l'un créé avec
File.createTempFile()
), vous aurez besoin de passer leREPLACE_EXISTING
option de copie (sinonFileAlreadyExistsException
est jeté):CopyOptions
paramètre.Files
n'est PAS disponible dans Android's de Java 1.7. J'ai été piqué par ceci: stackoverflow.com/questions/24869323/...Files.copy()
qui prend deux cours d'eau, et est ce que tous les autresFiles.copy()
fonctions de l'avant afin de faire le travail de copie. Cependant, il est privé (car il ne fait pas les impliquer les Chemins ou les Fichiers à ce stade), et regarde exactement comme le code dans le cas des OP propre question (en plus d'une instruction de retour). Pas d'ouverture, pas de fermeture, juste une copie de la boucle.InputStream.transferTo(OutputStream)
. stackoverflow.com/a/39440936/1441122Files.copy
n'ont pas en arrière support pour l'API en dessous de 26 @user1079877Je pense que cela va fonctionner, mais assurez-vous de le tester... mineur "amélioration", mais il pourrait être un peu d'un coût à la lisibilité.
while(len > 0)
au lieu de!= -1
, parce que cette dernière pourrait également renvoyer 0 lors de l'utilisation de laread(byte b[], int off, int len)
-méthode, qui déclenche une exception @out.write
InputStream
contrat de lecture pour retourner 0 un nombre quelconque de fois. Et selon laOutputStream
contrat, la méthode d'écriture doit accepter une longueur de 0, et ne doit lever une exception lorsquelen
est négatif.while
à unfor
et de mettre l'une des variables pour l'initialisation de l'article: par exemple,for (int n ; (n = in.read(buf)) != -1 ;) out.write(buf, 0, n);
. =)write()
n' pas lancer une exception si vous fournissez une longueur nulle.InputStream.read(byte[] b)
pour revenir à 0 (sauf si vous êtes stupide comme EJP dit: Si la longueur de b est égal à zéro, alors pas d'octets sont lus et la valeur renvoyée est 0; sinon, il y a une tentative de lecture d'au moins un octet. Si aucun octet est disponible, car le flux est à la fin du fichier, la valeur -1 est renvoyée; sinon, au moins un octet est lu et stocké dans b.-1
. L'arrêt de la lecture et de rejeter les données restantes est au moins autant une erreur que de passer un tampon vide.À l'aide de la Goyave est
ByteStreams.copier()
:Files.copy
autant que possible. UtilisationByteStreams.copy
seulement si les deux flux ne sont FileInputStream/FileOutputStream.Fonction Simple
Si vous avez seulement besoin de cela pour écrire un
InputStream
à unFile
alors vous pouvez utiliser cette fonction simple:close()
appels enfinally
blocs, si?PipedInputStream
etPipedOutputStream
ne doit être utilisé lorsque vous avez plusieurs threads, comme noté par la Javadoc.Notez également que les flux d'entrée et les flux de sortie n'enroulez pas de n'importe quel thread interruptions avec
IOException
s... Donc, vous devriez envisager l'intégration d'une politique d'interruption de votre code:Ce serait un complément utile si vous prévoyez d'utiliser cette API pour la copie de gros volumes de données, ou des données de flux coincé pour un insupportablement longue période de temps.
La
JDK
utilise le même code de sorte qu'il semble qu'il y est pas "facile" sans maladroit de bibliothèques tierces (qui n'est probablement pas faire quoi que ce soit de toute façon). Ce qui suit est directement copié à partir dejava.nio.file.Files.java
:Pour ceux qui utilisent framework Spring il est utile de StreamUtils classe:
Ci-dessus n'est pas de fermer les volets. Si vous souhaitez que les flux fermé après la copie, l'utilisation FileCopyUtils classe à la place:
Il n'y a pas moyen de faire beaucoup plus facile avec le JDK méthodes, mais comme Apocalisp a déjà noté, vous n'êtes pas la seule à avoir cette idée: Vous pouvez utiliser IOUtils de Jakarta Commons IO, elle a aussi beaucoup d'autres choses utiles, que l'OMI devrait faire partie du JDK...
À l'aide de Java7 et try-with-resources, vient avec un simplifiée et lisible de la version.
Voici comment je fais avec le plus simple pour la boucle.
Utiliser Communes Net Util classe:
Un à mon humble avis plus minime fragment (qui a également plus étroitement les étendues de la longueur variable):
Comme une note de côté, je ne comprends pas pourquoi plus de gens ne les utilisent pas un
for
boucle, plutôt que d'opter pour unwhile
avec un attribuez-et-expression de test qui est considéré par certains comme des "pauvres" de style.for(int n = 0; (n = in.read(buffer)) > 0;) { out.write(buffer, 0, n); }
Je pense qu'il est préférable d'utiliser une mémoire tampon de grande taille, car la plupart des fichiers sont supérieurs à 1024 octets. Aussi c'est une bonne pratique pour vérifier le nombre d'octets lus à être positif.
PipedInputStream et PipedOutputStream peut être de quelque utilité, comme vous pouvez connecter l'un à l'autre.
Un autre candidat possible sont la Goyave I/O utilities:
http://code.google.com/p/guava-libraries/wiki/IOExplained
Je pensais utiliser ces depuis Goyave est déjà extrêmement utile dans mon projet, plutôt que d'ajouter encore une autre bibliothèque pour une fonction.
copy
ettoByteArray
méthodes de docs.guava-libraries.googlecode.com/git-history/release/javadoc/... (goyave appels d'entrée/sortie flux "octet flux" et les lecteurs/écrivains comme "char flux")- Je utiliser
BufferedInputStream
etBufferedOutputStream
pour supprimer la mise en mémoire tampon de la sémantique du codeC'est mon meilleur coup!!!!
Et ne pas utiliser
inputStream.transferTo(...)
parce que c'est trop générique.Votre code rendement sera meilleur si vous le contrôle de votre mémoire-tampon.
- Je l'utiliser avec ce (améliorable) méthode quand je sais à l'avance la taille du flux.
Essayer Cactoos:
Plus de détails ici: http://www.yegor256.com/2017/06/22/object-oriented-input-output-in-cactoos.html
vous pouvez utiliser cette méthode
catch(Exception ex){}
— c'est top