2013-05-16 63 views
12

我使用下面的方法来写InputStreamFile如何使用NIO将InputStream写入文件?

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

我想知道,这是使用NIO的正确途径。我已阅读的方法FileChannel.transferFrom,这需要三个参数:

  1. 的ReadableByteChannel SRC
  2. 多头
  3. 长计数

在我来说,我只有src,我没有positioncount,有没有什么办法可以使用这种方法来创建文件?

也为图像有没有更好的方式来创建图像只从InputStream和NIO?

任何信息对我来说都是非常有用的。在这里也有类似的问题,但我无法找到适合我的案例的任何特定解决方案。

+5

为什么这么复杂?你可以在一行中做同样的事情:'Files.copy(stream,new File(“C:\\ Test.jpg”)。toPath());' – Jesper

回答

7

不,这是不正确的。你冒着丢失数据的风险。规范NIO复制循环如下:

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

注意改变循环条件,这照顾冲洗在EOS的输出,以及使用的compact()代替clear(),这需要的短写的可能性照顾。

同样规范transferTo()/transferFrom()循环如下:

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

它必须在一个循环中被调用,因为它不保证传送整个量子。

+0

如果transferFrom返回0,这并不意味着所有的字节都是实际的转入。为了100%正确,我们需要事先知道InputStream的预期计数并循环,直到我们全部传输它们。你同意吗? –

+0

是的,我愿意。从这些API没有适当的EOS指示是一件奇怪的事情。 – EJP

37

我会用Files.copy

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

为您的版本

  1. ByteBuffer.allocateDirect更快 - Java将使得直接在其上执行本机I/O操作的最大的努力。

  2. 闭幕是不可靠的,如果第一次失败,第二次永远不会执行。使用try-with-resources代替,Channels也是AutoCloseable

+0

''transferFrom()'和'transferTo()'必须在循环中调用。无法保证他们转移了请求的计数。这就是为什么他们返回一个计数。 – EJP

+0

使用Files.copy(fileInputStream,filePath,StandardCopyOption。REPLACE_EXISTING);如果文件已经存在。 – Justas

相关问题