Łatwy sposób zapisu zawartości strumienia wejściowego Java do strumienia wyjściowego

Byłem zaskoczony, że dzisiaj nie mogłem wyśledzić żadnego prostego sposobu zapisu zawartości InputStream do OutputStream w Javie. Oczywiście kod bufora bajtowego nie jest trudny do napisania, ale podejrzewam, że brakuje mi czegoś, co ułatwiłoby mi życie (a kod jaśniejszy).

Więc, biorąc pod uwagę InputStream in oraz OutputStream out, czy istnieje prostszy sposób na napisanie następujących rzeczy?

byte[] buffer = new byte[1024];
int len = in.read(buffer);
while (len != -1) {
    out.write(buffer, 0, len);
    len = in.read(buffer);
}
 354
Author: ArtB, 2008-09-04

20 answers

Jeśli używasz Java 7, Files (w bibliotece standardowej) jest najlepszym podejściem:

/* You can get Path from file also: file.toPath() */
Files.copy(InputStream in, Path target)
Files.copy(Path source, OutputStream out)

Edit: oczywiście jest to po prostu przydatne, gdy tworzysz jeden z InputStream lub OutputStream z pliku. Użyj file.toPath(), Aby pobrać ścieżkę z pliku.

Aby zapisać w istniejącym pliku (np. utworzonym za pomocą File.createTempFile()), musisz przekazać opcję kopiowania REPLACE_EXISTING (w przeciwnym razie zostanie wyrzucone FileAlreadyExistsException):

Files.copy(in, target, StandardCopyOption.REPLACE_EXISTING)
 273
Author: user1079877,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-12-22 12:57:56

Jak wspomniano WMR, org.apache.commons.io.IOUtils z Apache ma metodę zwaną copy(InputStream,OutputStream) co robi dokładnie to, czego szukasz.

Więc masz:

InputStream in;
OutputStream out;
IOUtils.copy(in,out);
in.close();
out.close();

...w Twoim kodzie.

Czy jest jakiś powód, dla którego unikasz IOUtils?

 365
Author: Mikezx6r,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-09-23 15:36:50

Myślę, że to zadziała, ale upewnij się, że przetestujesz... niewielka "poprawa", ale może to być trochę koszt czytelności.

byte[] buffer = new byte[1024];
int len;
while ((len = in.read(buffer)) != -1) {
    out.write(buffer, 0, len);
}
 91
Author: Mike Stone,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-04 03:58:20

Java 9

Od wersji Java 9, InputStream dostarcza metodę o nazwie transferTo z następującym podpisem:

public long transferTo(OutputStream out) throws IOException

Jak stwierdza dokumentacja, transferTo będzie:

Odczytuje wszystkie bajty z tego strumienia wejściowego i zapisuje bajty do podany strumień wyjściowy w kolejności, w jakiej są odczytywane. Po powrocie, to strumień wejściowy będzie na końcu strumienia. Ta metoda nie zamyka albo strumień.

Ta metoda może blokować w nieskończoność odczyt z wejście stream lub zapis do strumienia wyjściowego. Zachowanie dla przypadek, w którym strumień wejściowy lub wyjściowy jest asynchronicznie zamknięty, lub wątek przerwany podczas transferu, jest wysoce wejściowy i wyjściowy strumień specyficzny, a zatem nie określony

Więc aby napisać zawartość Javy InputStream do OutputStream, możesz napisać:

input.transferTo(output);
 79
Author: Ali Dehghani,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-07 09:46:25

Używanie guawy ByteStreams.copy():

ByteStreams.copy(inputStream, outputStream);
 39
Author: Andrejs,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-25 00:00:28

Prosta Funkcja

Jeśli potrzebujesz tego tylko do napisania InputStream do File, możesz użyć tej prostej funkcji:

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
Author: Jordan LaPrise,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-01-24 23:11:15

PipedInputStream i PipedOutputStream powinny być używane tylko wtedy, gdy masz wiele wątków, jak zauważył Javadoc .

Należy również pamiętać, że strumienie wejściowe i wyjściowe nie zawierają przerw w wątku za pomocą IOExceptions... Dlatego powinieneś rozważyć włączenie polityki przerwania do swojego kodu:

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

Byłoby to przydatne, jeśli spodziewasz się używać tego API do kopiowania dużych ilości danych lub danych ze strumieni, które utkną przez nietolerancyjnie długi czas.

 14
Author: Dilum Ranatunga,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-19 16:27:14

JDK używa tego samego kodu, więc wydaje się, że nie ma "łatwiejszego" sposobu bez niezgrabnych bibliotek stron trzecich (które i tak pewnie nic nie robią inaczej). Poniżej jest bezpośrednio skopiowane z 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
Author: BullyWiiPlaza,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-13 11:10:11

Nie ma sposobu, aby zrobić to dużo łatwiej z metodami JDK, ale jak Apocalisp już zauważył, nie jesteś jedynym z tym pomysłem: możesz użyć IOUtils z Jakarta Commons IO, ma również wiele innych przydatnych rzeczy, które IMO powinny być częścią JDK...

 8
Author: WMR,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-04 10:50:10

Korzystanie z Java7 i try-with-resources , pochodzi z uproszczoną i czytelną wersją.

    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
Author: Sivakumar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-29 11:12:31

Dla tych, którzy używają Spring framework istnieje przydatna StreamUtils klasa:

StreamUtils.copy(in, out);

Powyższe nie zamyka strumieni. Jeśli chcesz, aby strumienie były zamknięte po skopiowaniu, Użyj klasy FileCopyUtils :

FileCopyUtils.copy(in, out);
 6
Author: holmis83,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-02 14:33:08

Użyj klasy Util Commons Net:

import org.apache.commons.net.io.Util;
...
Util.copyStream(in, out);
 4
Author: DejanLekic,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-11-11 20:56:35

Oto jak sobie radzę z najprostszą pętlą for.

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
Author: Jin Kwon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-22 01:17:50

Myślę, że lepiej jest użyć dużego bufora, ponieważ większość plików jest większa niż 1024 bajty. Dobrą praktyką jest również sprawdzanie, czy liczba odczytanych bajtów jest dodatnia.

byte[] buffer = new byte[4096];
int n;
while ((n = in.read(buffer)) > 0) {
    out.write(buffer, 0, n);
}
out.close();
 2
Author: Alexander Volkov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-09-13 14:24:37

IMHO bardziej minimalistyczny snippet (który również wąsko zakreśla zmienną długości):

byte[] buffer = new byte[2048];
for (int n = in.read(buffer); n >= 0; n = in.read(buffer))
    out.write(buffer, 0, n);

Na marginesie, nie rozumiem, dlaczego więcej osób nie używa pętli for, zamiast tego decyduje się na while z wyrażeniem assign-and-test, które jest uważane przez niektórych za "kiepski" styl.

 2
Author: Bohemian,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-08 04:27:43

PipedInputStream i PipedOutputStream mogą być przydatne, ponieważ można je połączyć z innymi.

 0
Author: Arktronic,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-04 04:04:07

Innym możliwym kandydatem są narzędzia I/O Guava:

Http://code.google.com/p/guava-libraries/wiki/IOExplained

Pomyślałem, że skorzystam z nich, ponieważ Guava jest już niezwykle przydatna w moim projekcie, zamiast dodawać kolejną bibliotekę dla jednej funkcji.

 0
Author: Andrew Mao,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-11 05:42:34

Try Cactoos :

new LengthOf(new TeeInput(input, output)).value();

Więcej szczegółów tutaj: http://www.yegor256.com/2017/06/22/object-oriented-input-output-in-cactoos.html

 0
Author: yegor256,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
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
Author: Nour Rteil,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-04-02 18:48:24

Możesz użyć tej metody

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
Author: Pranav,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-06 11:23:20