如何使用 NIO 将 InputStream 写入 File?

Posted

技术标签:

【中文标题】如何使用 NIO 将 InputStream 写入 File?【英文标题】:How to use NIO to write InputStream to File? 【发布时间】:2013-05-11 00:13:20 【问题描述】:

我正在使用以下方式将InputStream 写入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();

我想知道这是否是使用 NIO 的正确方法。我看过一个方法FileChannel.transferFrom,它需要三个参数:

    ReadableByteChannel src 多头 长计数

就我而言,我只有src,我没有positioncount,有什么方法可以使用这种方法来创建文件吗?

对于 Image 还有没有更好的方法来仅从 InputStream 和 NIO 创建图像?

任何信息都会对我非常有用。这里有类似的问题,在 SO 中,但我找不到适合我的情况的任何特定解决方案。

【问题讨论】:

为什么要这么复杂?您可以在一行中执行相同的操作:Files.copy(stream, new File("C:\\Test.jpg").toPath()); 【参考方案1】:

我会使用 Files.copy

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

至于你的版本

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

    关闭是不可靠的,如果第一次失败,第二次将永远不会执行。请改用 try-with-resources,Channel 也是 AutoCloseable

【讨论】:

transferFrom()transferTo() 必须在循环中调用。不能保证他们会转移请求的计数。这就是他们返回计数的原因。 使用 Files.copy(fileInputStream, filePath, StandardCopyOption.REPLACE_EXISTING);如果文件已经存在。【参考方案2】:

不,这是不正确的。您冒着丢失数据的风险。规范的 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;

它必须在循环中调用,因为它不能保证传输整个量程。

【讨论】:

如果 transferFrom 返回 0 并不意味着所有字节都被实际传输。为了 100% 正确,我们需要提前知道 InputStream 的预期计数并循环,直到我们将它们全部传输。你同意吗? 是的,我愿意。奇怪的是,这些 API 没有正确指示 EOS。

以上是关于如何使用 NIO 将 InputStream 写入 File?的主要内容,如果未能解决你的问题,请参考以下文章

将 InputStream 写入文件 [重复]

NIO 的工作方式

java如何将一个InputStream写入文件?

将 InputStream 写入 HttpServletResponse

Java NIO之Channel

文件读写操作inputStream转为byte[] , 将InputStream写入本地文件