Méthode facile pour écrire le contenu D'un flux entrant Java vers un flux sortant
j'ai été surpris de constater aujourd'hui que je ne pouvais trouver aucune façon simple d'écrire le contenu d'un InputStream
à un OutputStream
en Java. Évidemment, le code tampon byte n'est pas difficile à écrire, mais je soupçonne que je suis juste en train de manquer quelque chose qui rendrait ma vie plus facile (et le code plus clair).
ainsi, étant donné un InputStream
in
et un OutputStream
out
, y a-t-il une façon 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);
}
20 réponses
Si vous utilisez Java 7, Fichiers (dans la bibliothèque standard) est la meilleure approche:
/* You can get Path from file also: file.toPath() */
Files.copy(InputStream in, Path target)
Files.copy(Path source, OutputStream out)
Edit: bien sûr, c'est juste utile lorsque vous créez un de InputStream ou OutputStream à partir d'un fichier. Utilisez file.toPath()
pour obtenir le chemin à partir du fichier.
pour écrire dans un fichier existant (par exemple celui créé avec File.createTempFile()
), vous devrez passer l'option REPLACE_EXISTING
copie (sinon FileAlreadyExistsException
est lancé):
Files.copy(in, target, StandardCopyOption.REPLACE_EXISTING)
comme WMR l'a mentionné, org.apache.commons.io.IOUtils
de Apache a une méthode appelée copy(InputStream,OutputStream)
qui fait exactement ce que vous cherchez.
donc, vous avez:
InputStream in;
OutputStream out;
IOUtils.copy(in,out);
in.close();
out.close();
... dans votre code.
y a-t-il une raison pour éviter IOUtils
?
je 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é.
byte[] buffer = new byte[1024];
int len;
while ((len = in.read(buffer)) != -1) {
out.write(buffer, 0, len);
}
Java 9
depuis Java 9, InputStream
fournit une méthode appelée transferTo
avec la signature suivante:
public long transferTo(OutputStream out) throws IOException
comme le documentation stipule, transferTo
will:
lit tous les octets de ce flux d'entrée et écrit les octets à la donné le flux de sortie dans l'ordre où ils sont lus. Sur le retour, cette flux d'entrée sera à la fin du flux. Ce la méthode ne se termine pas un ou l'autre volet.
cette méthode peut bloquer indéfiniment la lecture flux d'entrée ou écriture sur le flux de sortie. Le comportement pour le cas où l'entrée et/ou sortie de flux de manière asynchrone fermé, ou le thread interrompu pendant le transfert, est fortement entrée et sortie flux spécifiques, et ne sont donc pas spécifiées
ainsi afin d'écrire le contenu D'un Java InputStream
à un OutputStream
, vous pouvez écrire:
input.transferTo(output);
utilisant la goyave ByteStreams.copy()
:
ByteStreams.copy(inputStream, outputStream);
Simple "Fonction De 151940920"
si vous n'en avez besoin que pour écrire un InputStream
à un File
alors vous pouvez utiliser cette fonction simple:
private void copyInputStreamToFile( InputStream in, File file ) {
try {
OutputStream out = new FileOutputStream(file);
byte[] buf = new byte[1024];
int len;
while((len=in.read(buf))>0){
out.write(buf,0,len);
}
out.close();
in.close();
} catch (Exception e) {
e.printStackTrace();
}
}
PipedInputStream
et PipedOutputStream
ne doit être utilisé que lorsque vous avez plusieurs fils, comme noté par le Javadoc .
aussi, notez que les flux d'entrée et les flux de sortie n'enveloppent aucune interruption de thread avec IOException
s... Ainsi, vous devriez envisager d'incorporer une politique d'interruption à votre code:
byte[] buffer = new byte[1024];
int len = in.read(buffer);
while (len != -1) {
out.write(buffer, 0, len);
len = in.read(buffer);
if (Thread.interrupted()) {
throw new InterruptedException();
}
}
ce serait un ajout utile si vous prévoyez d'utiliser cette API pour copier de grands volumes de des données, ou des données provenant de flux qui restent bloqués pendant une durée intolérable.
le JDK
utilise le même code de sorte qu'il semble qu'il n'y ait pas de moyen "plus facile" sans bibliothèques tierces (qui ne font probablement rien de différent de toute façon). Ce qui suit est directement copié de java.nio.file.Files.java
:
// buffer size used for reading and writing
private static final int BUFFER_SIZE = 8192;
/**
* Reads all bytes from an input stream and writes them to an output stream.
*/
private static long copy(InputStream source, OutputStream sink)
throws IOException
{
long nread = 0L;
byte[] buf = new byte[BUFFER_SIZE];
int n;
while ((n = source.read(buf)) > 0) {
sink.write(buf, 0, n);
nread += n;
}
return nread;
}
il n'y a pas moyen de faire cela beaucoup plus facile avec les méthodes JDK, mais comme Apocalisp a déjà noté, vous n'êtes pas le seul avec cette idée: vous pourriez utiliser IOUtils de Jakarta Commons IO , il a également beaucoup d'autres choses utiles, que L'OMI devrait en fait faire partie de la JDK...
en utilisant Java7 et try-with-resources , est livré avec une version simplifiée et lisible.
try(InputStream inputStream = new FileInputStream("C:\mov.mp4");
OutputStream outputStream = new FileOutputStream("D:\mov.mp4")){
byte[] buffer = new byte[10*1024];
for (int length; (length = inputStream.read(buffer)) != -1; ){
outputStream.write(buffer, 0, length);
}
}catch (FileNotFoundException exception){
exception.printStackTrace();
}catch (IOException ioException){
ioException.printStackTrace();
}
Pour ceux qui utilisent Spring il est utile de StreamUtils classe:
StreamUtils.copy(in, out);
ce qui précède ne ferme pas les ruisseaux. Si vous voulez que les flux soient fermés après la copie, utilisez FileCopyUtils class instead:
FileCopyUtils.copy(in, out);
utiliser la classe Util de Commons Net:
import org.apache.commons.net.io.Util;
...
Util.copyStream(in, out);
voilà comment je m'en sors avec le plus simple pour loop.
private void copy(final InputStream in, final OutputStream out)
throws IOException {
final byte[] b = new byte[8192];
for (int r; (r = in.read(b)) != -1;) {
out.write(b, 0, r);
}
}
je pense qu'il est préférable d'utiliser un grand tampon, parce que 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.
byte[] buffer = new byte[4096];
int n;
while ((n = in.read(buffer)) > 0) {
out.write(buffer, 0, n);
}
out.close();
A mon humble avis plus minime fragment (qui a également plus étroitement les étendues de la longueur variable):
byte[] buffer = new byte[2048];
for (int n = in.read(buffer); n >= 0; n = in.read(buffer))
out.write(buffer, 0, n);
comme note secondaire, Je ne comprends pas pourquoi plus de gens n'utilisent pas une boucle for
, optant plutôt pour une while
avec une expression assign-and-test qui est considérée par certains comme" pauvre " style.
PipedInputStream et PipedOutputStream peuvent être utiles, car vous pouvez vous connecter l'un à l'autre.
un autre candidat possible sont les utilités D'e/s de la goyave:
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.
Try Cactoos :
new LengthOf(new TeeInput(input, output)).value();
plus de détails ici: http://www.yegor256.com/2017/06/22/object-oriented-input-output-in-cactoos.html
public static boolean copyFile(InputStream inputStream, OutputStream out) {
byte buf[] = new byte[1024];
int len;
long startTime=System.currentTimeMillis();
try {
while ((len = inputStream.read(buf)) != -1) {
out.write(buf, 0, len);
}
long endTime=System.currentTimeMillis()-startTime;
Log.v("","Time taken to transfer all bytes is : "+endTime);
out.close();
inputStream.close();
} catch (IOException e) {
return false;
}
return true;
}
vous pouvez utiliser cette méthode""
public static void copyStream(InputStream is, OutputStream os)
{
final int buffer_size=1024;
try
{
byte[] bytes=new byte[buffer_size];
for(;;)
{
int count=is.read(bytes, 0, buffer_size);
if(count==-1)
break;
os.write(bytes, 0, count);
}
}
catch(Exception ex){}
}