2013-05-16 16 views
12

Ich verwende folgende Weise InputStream-File zu schreiben:Wie NIO verwenden, um InputStream in Datei zu schreiben?

private void writeToFile(InputStream stream) throws IOException { 
    String filePath = "C:\\Test.jpg"; 
    FileChannel outChannel = new FileOutputStream(filePath).getChannel();  
    ReadableByteChannel inChannel = Channels.newChannel(stream); 
    ByteBuffer buffer = ByteBuffer.allocate(1024); 

    while(true) { 
     if(inChannel.read(buffer) == -1) { 
      break; 
     } 

     buffer.flip(); 
     outChannel.write(buffer); 
     buffer.clear(); 
    } 

    inChannel.close(); 
    outChannel.close(); 
} 

Ich frage mich, ob dies der richtige Weg NIO zu bedienen ist. Ich habe eine Methode FileChannel.transferFrom, lesen Sie die drei Parameter übernimmt:

  1. ReadableByteChannel src
  2. Long-Position
  3. lange Zählung

In meinem Fall habe ich nur src haben, ich habe nicht die position und count, gibt es eine Möglichkeit, wie ich diese Methode verwenden kann, um die Datei zu erstellen?

Auch für Bild gibt es eine bessere Möglichkeit, nur Bild von InputStream und NIO zu erstellen?

Jede Information wäre sehr nützlich für mich. Es gibt ähnliche Fragen hier in SO, aber ich kann keine bestimmte Lösung finden, die zu meinem Fall passt.

+5

Warum so kompliziert? Sie können dasselbe in einer Zeile machen: 'Files.copy (stream, neue Datei (" C: \\ Test.jpg "). ToPath());' – Jesper

Antwort

7

Nein, es ist nicht korrekt. Sie laufen Gefahr, Daten zu verlieren. Die kanonische NIO Kopie Schleife ist wie folgt:

while (in.read(buffer) >= 0 || buffer.position() > 0) 
{ 
    buffer.flip(); 
    out.write(buffer); 
    buffer.compact(); 
} 

Beachten Sie die geänderten Schleifenbedingungen, die die Ausgabe bei EOS der Spülung sorgen, und die Verwendung von compact() statt clear(),, die sich um die Möglichkeit einer kurzen schreibt nimmt.

ähnlich die kanonische transferTo()/transferFrom() Schleife ist wie folgt:

long offset = 0; 
long quantum = 1024*1024; // or however much you want to transfer at a time 
long count; 
while ((count = out.transferFrom(in, offset, quantum)) > 0) 
{ 
    offset += count; 
} 

Es muss in einer Schleife aufgerufen werden, da es nicht garantiert wird, um die gesamten Quanten zu übertragen.

+0

Wenn transferFrom 0 zurückgibt, bedeutet das nicht, dass alle Bytes tatsächlich sind übertragen. Um 100% korrekt zu sein, müssen wir im Voraus die erwartete Anzahl von InputStream und Schleife wissen, bis wir sie alle übertragen. Sind Sie einverstanden? –

+0

Ja, das tue ich. Es ist eine seltsame Sache, dass es keine richtige EOS-Indikation von diesen APIs gibt. – EJP

37

würde ich für Ihre Version verwenden Files.copy

Files.copy(is, Paths.get(filePath)); 

als

  1. ByteBuffer.allocateDirect ist schneller - Java wird eine Anstrengung unternehmen nativer auszuführen I/O-Operationen direkt darauf.

  2. Schließen ist unzuverlässig, wenn die erste fehlschlägt, wird die zweite nie ausgeführt. Verwenden Sie stattdessen try-with-resources, Kanäle sind AutoCloseable auch.

+0

'transferFrom()' und 'transferTo()' müssen in einer Schleife aufgerufen werden. Es gibt keine Garantie, dass sie die angeforderte Anzahl übertragen. Deshalb geben sie eine Zählung zurück. – EJP

+0

Verwenden Sie Files.copy (fileInputStream, filePath, StandardCopyOption.EXISTIERENDES ERSETZEN); wenn die Datei bereits existiert. – Justas