Einfache Möglichkeit, Inhalte eines Java InputStream in einen OutputStream zu schreiben

StackOverflow https://stackoverflow.com/questions/43157

  •  09-06-2019
  •  | 
  •  

Frage

Ich war überrascht, heute festzustellen, dass ich keine einfache Möglichkeit finden konnte, den Inhalt eines zu schreiben InputStream zu einem OutputStream in Java.Offensichtlich ist der Byte-Puffer-Code nicht schwer zu schreiben, aber ich vermute, dass mir einfach etwas fehlt, das mir das Leben einfacher (und den Code klarer) machen würde.

Also, angesichts einer InputStream in und ein OutputStream out, Gibt es eine einfachere Möglichkeit, Folgendes zu schreiben?

byte[] buffer = new byte[1024];
int len = in.read(buffer);
while (len != -1) {
    out.write(buffer, 0, len);
    len = in.read(buffer);
}
War es hilfreich?

Lösung

Wenn Sie Java 7 verwenden, Dateien (in der Standardbibliothek) ist der beste Ansatz:

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

Bearbeiten:Natürlich ist es nur nützlich, wenn Sie einen InputStream oder OutputStream aus einer Datei erstellen.Verwenden file.toPath() um den Pfad aus der Datei zu erhalten.

Um in eine bestehende Datei zu schreiben (z.B.einer erstellt mit File.createTempFile()), müssen Sie die bestehen REPLACE_EXISTING Kopieroption (sonst FileAlreadyExistsException ist geworfen):

Files.copy(in, target, StandardCopyOption.REPLACE_EXISTING)

Andere Tipps

Wie WMR erwähnte, org.apache.commons.io.IOUtils von Apache hat eine Methode namens copy(InputStream,OutputStream) das genau das tut, was Sie suchen.

Also hast du:

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

...in deinem Code.

Gibt es einen Grund, warum Sie es meiden? IOUtils?

Java 9

Seit Java 9, InputStream stellt eine Methode namens bereit transferTo mit folgender Signatur:

public long transferTo(OutputStream out) throws IOException

Als die Dokumentation Zustände, transferTo Wille:

Liest alle Bytes aus diesem Eingabestream und schreibt die Bytes in den angegebenen Ausgangsstrom in der Reihenfolge, in der sie gelesen werden.Bei der Rückkehr befindet sich dieser Eingangsstrom am Ende des Streams.Diese Methode schließt keiner Stream.

Diese Methode kann auf unbestimmte Zeit aus dem Eingabestream blockieren oder in den Ausgabestream schreiben.Das Verhalten für den Fall, in dem der Eingangs- und/oder Ausgangsstrom asynchron geschlossen oder während der Übertragung unterbrochen wird, ist stark Eingangs- und Ausgangsstromspezifikationen und daher nicht angegeben

Also um Inhalte eines Java zu schreiben InputStream zu einem OutputStream, Du kannst schreiben:

input.transferTo(output);

Ich denke, das wird funktionieren, aber testen Sie es unbedingt ...Kleinere „Verbesserung“, aber die Lesbarkeit könnte etwas darunter leiden.

byte[] buffer = new byte[1024];
int len;
while ((len = in.read(buffer)) != -1) {
    out.write(buffer, 0, len);
}

Verwendung von Guaven ByteStreams.copy():

ByteStreams.copy(inputStream, outputStream);

Einfache Funktion

Wenn Sie dies nur zum Schreiben einer benötigen InputStream zu einem File Dann können Sie diese einfache Funktion verwenden:

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 Und PipedOutputStream sollte nur verwendet werden, wenn Sie mehrere Threads haben, z vom Javadoc notiert.

Beachten Sie außerdem, dass Eingabestreams und Ausgabestreams keine Thread-Unterbrechungen mit einschließen IOExceptionS...Daher sollten Sie erwägen, eine Unterbrechungsrichtlinie in Ihren Code zu integrieren:

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

Dies wäre eine nützliche Ergänzung, wenn Sie diese API zum Kopieren großer Datenmengen oder von Daten aus Streams verwenden möchten, die unerträglich lange hängen bleiben.

Der JDK verwendet den gleichen Code, daher scheint es keinen „einfacheren“ Weg ohne klobige Bibliotheken von Drittanbietern zu geben (die wahrscheinlich sowieso nichts anderes machen).Das Folgende wird direkt kopiert 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;
    }

Für diejenigen, die es verwenden Federrahmen es gibt ein nützliches StreamUtils Klasse:

StreamUtils.copy(in, out);

Dadurch werden die Streams nicht geschlossen.Wenn Sie möchten, dass die Streams nach dem Kopieren geschlossen werden, verwenden Sie FileCopyUtils Klasse stattdessen:

FileCopyUtils.copy(in, out);

Mit JDK-Methoden geht das nicht viel einfacher, aber wie Apocalsp bereits bemerkt hat, sind Sie nicht der Einzige mit dieser Idee:Du könntest benutzen IOUtils aus Jakarta Commons IO, es hat auch viele andere nützliche Dinge, die meiner Meinung nach eigentlich Teil des JDK sein sollten ...

Mit Java7 und Versuchen Sie es mit Ressourcen, kommt mit einer vereinfachten und lesbaren Version.

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

Verwenden Sie die Util-Klasse von Commons Net:

import org.apache.commons.net.io.Util;
...
Util.copyStream(in, out);

Hier erfahren Sie, wie ich es mit der einfachsten for-Schleife mache.

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

Ein meiner Meinung nach minimalerer Ausschnitt (der auch die Längenvariable enger begrenzt):

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

Nebenbei bemerkt verstehe ich nicht, warum nicht mehr Leute a verwenden for Schleife, stattdessen entscheiden Sie sich für a while mit einem Zuweisungs- und Testausdruck, der von manchen als „schlechter“ Stil angesehen wird.

Ich denke, es ist besser, einen großen Puffer zu verwenden, da die meisten Dateien größer als 1024 Byte sind.Außerdem empfiehlt es sich, zu überprüfen, ob die Anzahl der gelesenen Bytes positiv ist.

byte[] buffer = new byte[4096];
int n;
while ((n = in.read(buffer)) > 0) {
    out.write(buffer, 0, n);
}
out.close();

PipedInputStream und PipedOutputStream können von Nutzen sein, da Sie sie miteinander verbinden können.

Ein weiterer möglicher Kandidat sind die Guava I/O-Dienstprogramme:

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

Ich dachte, ich würde diese verwenden, da Guava in meinem Projekt bereits äußerst nützlich ist, anstatt noch eine weitere Bibliothek für eine Funktion hinzuzufügen.

ich benutze BufferedInputStream Und BufferedOutputStream um die Puffersemantik aus dem Code zu entfernen

try (OutputStream out = new BufferedOutputStream(...);
     InputStream in   = new BufferedInputStream(...))) {
  int ch;
  while ((ch = in.read()) != -1) {
    out.write(ch);
  }
}
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;
}

Versuchen Kakteen:

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

Weitere Details hier: http://www.yegor256.com/2017/06/22/object-oriented-input-output-in-cactoos.html

Sie können diese Methode verwenden

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){}
 }
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top