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);
}
354
demandé sur ArtB 2008-09-04 07:46:16

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)
273
répondu user1079877 2015-12-22 12:57:56

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 ?

365
répondu Mikezx6r 2014-09-23 15:36:50

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);
}
91
répondu Mike Stone 2008-09-04 03:58:20

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);
79
répondu Ali Dehghani 2018-03-07 09:46:25

utilisant la goyave ByteStreams.copy() :

ByteStreams.copy(inputStream, outputStream);
39
répondu Andrejs 2016-02-25 00:00:28

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();
    }
}

24
répondu Jordan LaPrise 2015-01-24 23:11:15

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.

14
répondu Dilum Ranatunga 2015-08-19 16:27:14

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;
    }
10
répondu BullyWiiPlaza 2016-10-13 11:10:11

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...

8
répondu WMR 2008-09-04 10:50:10

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();
    }
7
répondu Sivakumar 2016-07-29 11:12:31

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);
6
répondu holmis83 2017-02-02 14:33:08

utiliser la classe Util de Commons Net:

import org.apache.commons.net.io.Util;
...
Util.copyStream(in, out);
4
répondu DejanLekic 2013-11-11 20:56:35

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);
    }
}
3
répondu Jin Kwon 2016-08-22 01:17:50

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();
2
répondu Alexander Volkov 2013-09-13 14:24:37

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.

2
répondu Bohemian 2016-02-08 04:27:43

PipedInputStream et PipedOutputStream peuvent être utiles, car vous pouvez vous connecter l'un à l'autre.

0
répondu Arktronic 2008-09-04 04:04:07

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.

0
répondu Andrew Mao 2012-12-11 05:42:34

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

0
répondu yegor256 2017-09-21 16:06:09
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;
}
-2
répondu Nour Rteil 2015-04-02 18:48:24

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){}
 }
-5
répondu Pranav 2014-03-06 11:23:20