如何使用NIO将输入流写入文件?

2022-09-02 05:10:52

我使用以下方式写到:InputStreamFile

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. 可读字节通道 src
  2. 多头仓位
  3. 长计数

在我的情况下,我只有,我没有和,有没有办法使用这种方法来创建文件?srcpositioncount

另外,对于图像,有没有更好的方法只从和NIO创建图像?InputStream

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


答案 1

我会使用Files.copy

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

至于你的版本

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

  2. 关闭是不可靠的,如果第一个失败,第二个将永远不会执行。请改用资源试用,Channel 也是如此。AutoCloseable


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

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