2016-12-24 90 views
-3

我在写一个java rest服务来支持大文件的部分并行上传。我正在将这些部分写入单独的文件中,并使用文件通道合并它们。我有一个在Golang中实现的示例,它执行相同的操作,但是它在合并这些部分时不需要时间。当我使用文件通道或从一个流中读取并写入最终文件时,需要很长时间。我认为这种差异在于,Golang有能力将数据保存在磁盘上,并通过不实际移动数据来合并它们。有什么办法可以在java中做同样的事情吗? 这里是我的代码,通过这种方法对所有部件合并部分,我循环:在java中更快地合并大文件部分

private void mergeFileUsingChannel(String destinationPath, String sourcePath, long partSize, long offset) throws Exception{ 
    FileChannel outputChannel = null; 
    FileChannel inputChannel = null; 
    try{ 
     outputChannel = new FileOutputStream(new File(destinationPath)).getChannel(); 
     outputChannel.position(offset); 

     inputChannel = new FileInputStream(new File(sourcePath)).getChannel(); 
     inputChannel.transferTo(0, partSize, outputChannel); 
    }catch(Exception e){ 
     e.printStackTrace(); 
    } 
    finally{ 
     if(inputChannel != null) 
      inputChannel.close(); 
     if(outputChannel != null){ 
      outputChannel.close(); 
     } 
    } 

} 
+0

操作系统和文件系统类型可能与此问题有关吗? –

+0

服务器是fedora 24.我不确定文件系统。我正在将文件传输到HDD,SSD和网络位置。 –

回答

0

FileChanneltransferTo状态的文档:

“很多操作系统都可以直接从文件系统缓存传输的字节到目标频道而无需实际复制它们。“

因此,您编写的代码是正确的,而且您看到的低效率可能与底层文件系统类型有关。

我可以建议的一个小优化就是在append模式下打开文件。

“无论是位置和数据写入的进步在单个原子操作中取决于系统”

除此之外,你可能不得不想办法工作围绕这个问题。例如,通过创建足够大的连续文件作为第一步。


编辑:我也注意到,您没有显式关闭FileOutputStream中。最好坚持并关闭它,以便所有文件描述符都关闭。

+1

所以我尝试了几个组合,并得出结论,它的操作系统和文件系统使I/O操作变得缓慢或快速。我尝试使用NTFS和ext4格式化硬盘连接到USB端口,并得到相同的结果(1分25秒合并30GB的1GB文件)。当我在我的Windows机器上尝试相同的硬盘时,它不到10秒。我现在正在阅读文件系统以及操作系统如何管理I/O。如果任何人有一个很好的链接阅读,我会很感激。另外,我看了一下GoLang示例,它有一个技巧,它在文件到达服务器时将文件的一部分合并到最后的罚款中,而不是最后。 –

+0

标记为已回答,因为我使用了我发布的相同方法。合并的时间依赖于媒体本身。 Java的NIO在合并中使用channel的transferrto方法来避免上下文切换和缓冲区复制。我需要考虑客户端 - 服务器连接(LAN/WAN)和目标媒体类型,以充分利用我的设置,谢谢! –