Java 如何使用 NIO 将 InputStream 写入文件?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16581724/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-16 07:33:15  来源:igfitidea点击:

How to use NIO to write InputStream to File?

javaimagefileinputstreamnio

提问by Tapas Bose

I am using following way to write InputStreamto File:

我使用下面的方法来写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();
}

I was wondering if this is the right way to use NIO. I have read a method FileChannel.transferFrom, which takes three parameter:

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

  1. ReadableByteChannel src
  2. long position
  3. long count
  1. ReadableByteChannel src
  2. 多头头寸
  3. 长数

In my case I only have src, I don't have the positionand count, is there any way I can use this method to create the file?

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

Also for Image is there any better way to create image only from InputStreamand NIO?

同样对于 Image 有没有更好的方法来仅从InputStreamNIO创建图像?

Any information would be very useful to me. There are similar questions here, in SO, but I cannot find any particular solution which suites my case.

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

采纳答案by user207421

No it's not correct. You run the risk of losing data. The canonical NIO copy loop is as follows:

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

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

Note the changed loop conditions, which take care of flushing the output at EOS, and the use of compact()instead of clear(),which takes care of the possibility of short writes.

请注意更改的循环条件,它负责在 EOS 上刷新输出,而使用compact()代替clear(),则负责短写入的可能性。

Similarly the canonical transferTo()/transferFrom()loop is as follows:

类似地,规范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;
}

It must be called in a loop, as it isn't guaranteed to transfer the entire quantum.

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

回答by Evgeniy Dorofeev

I would use Files.copy

我会使用 Files.copy

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

as for your version

至于你的版本

  1. ByteBuffer.allocateDirectis faster - Java will make a best effort to perform native I/O operations directly upon it.

  2. Closing is unreliable, if first fails second will never execute. Use try-with-resources instead, Channels are AutoCloseabletoo.

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

  2. 关闭是不可靠的,如果第一个失败,第二个将永远不会执行。使用 try-with-resources 代替,ChannelsAutoCloseable也是。