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

Java 如何使用NIO将InputStream写入文件?,java,image,file,inputstream,nio,Java,Image,File,Inputstream,Nio,我正在使用以下方法将输入流写入文件: private void writeToFile(InputStream stream) throws IOException { String filePath = "C:\\Test.jpg"; FileChannel outChannel = new FileOutputStream(filePath).getChannel(); ReadableByteChannel inChannel =

我正在使用以下方法将
输入流
写入
文件

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的正确方法。我读过一个方法,它采用三个参数:

  • Techannel src可读
  • 多头
  • 长计数
  • 在我的情况下,我只有
    src
    ,没有
    位置
    计数
    ,是否有任何方法可以使用此方法创建文件

    对于图像,是否有更好的方法仅从
    InputStream
    和NIO创建图像


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

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

    while (in.read(buffer) >= 0 || buffer.position() > 0)
    {
      buffer.flip();
      out.write(buffer);
      buffer.compact();
    }
    
    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;
    }
    
    请注意已更改的循环条件,它负责在EOS刷新输出,以及使用
    compact()
    代替
    clear(),
    来处理短写的可能性

    类似地,规范的
    transferTo()/transferFrom()
    循环如下所示:

    while (in.read(buffer) >= 0 || buffer.position() > 0)
    {
      buffer.flip();
      out.write(buffer);
      buffer.compact();
    }
    
    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;
    }
    
    它必须在循环中调用,因为它不能保证传输整个量子。

    我会使用Files.copy

    Files.copy(is, Paths.get(filePath));
    
    至于你的版本

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

  • 关闭是不可靠的,如果第一个失败,第二个将永远不会执行。改用try with resources,频道也是可自动关闭的


  • 为什么这么复杂?您可以在一行中执行相同的操作:
    Files.copy(流,新文件(“C:\\Test.jpg”).toPath()
    transferFrom()
    transferTo()
    必须在循环中调用。无法保证他们会转移请求的计数。这就是它们返回计数的原因。使用Files.copy(fileInputStream、filePath、StandardCopyOption.REPLACE_EXISTING);如果文件已存在。如果transferFrom返回0,则并不意味着所有字节都已实际传输。为了100%正确,我们需要提前知道InputStream和loop的预期计数,直到我们将它们全部传输。你同意吗?是的,我同意。奇怪的是,这些API没有正确的EOS指示。