2013-05-16 12 views
12

Sto usando seguente modo di scrivere InputStream-File:Come utilizzare NIO per scrivere InputStream su File?

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

mi chiedevo se questo è il modo giusto di usare NIO. Ho letto un metodo FileChannel.transferFrom, che prende tre parametri:

  1. ReadableByteChannel src
  2. posizione lunga
  3. lungo conto

Nel mio caso ho solo src, non ho il position e count, esiste un modo per utilizzare questo metodo per creare il file?

Anche per Immagine esiste un modo migliore per creare l'immagine solo da InputStream e NIO?

Qualsiasi informazione sarebbe molto utile per me. Ci sono domande simili qui, in SO, ma non riesco a trovare nessuna soluzione particolare che soddisfi il mio caso.

+5

Perché farlo in un modo così complicato? Puoi fare lo stesso in una riga: 'Files.copy (stream, new File (" C: \\ Test.jpg "). ToPath());' – Jesper

risposta

7

No, non è corretto. Corri il rischio di perdere dati. Il ciclo copia NIO canonica è la seguente:

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

Nota le condizioni di loop mutate, che si prendono cura di vampate di calore l'uscita a EOS, e l'uso di compact() invece di clear(), che si prende cura della possibilità di brevi operazioni di scrittura.

Analogamente la canonica transferTo()/transferFrom() ciclo è il seguente:

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

esso deve essere richiamato in un ciclo, in quanto non è garantito per trasferire l'intera quantistico.

+0

Se transferFrom restituisce 0 non significa che tutti i byte siano effettivamente trasferiti. Per essere corretti al 100%, dobbiamo conoscere in anticipo il conteggio previsto da InputStream e il ciclo fino a quando non li trasferiamo tutti. Sei d'accordo? –

+0

Sì, sì. È strano che non ci sia un'indicazione EOS corretta da queste API. – EJP

37

userei Files.copy

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

come per la versione

  1. ByteBuffer.allocateDirect è più veloce - Java farà un miglior sforzo per eseguire nativi operazioni di I/O direttamente su di essa.

  2. La chiusura non è affidabile, se il primo errore non verrà eseguito. Utilizza invece try-with-resources, anche i canali sono AutoCloseable.

+0

'transferFrom()' e 'transferTo()' deve essere chiamato in un ciclo. Non vi è alcuna garanzia che trasferiscano il conteggio richiesto. Ecco perché restituiscono un conteggio. – EJP

+0

Usa Files.copy (fileInputStream, filePath, StandardCopyOption.Replace_existing); se il file esiste già. – Justas

Problemi correlati