Java 以尽可能快的方式复制大文件
我试图找到一种以最快的方式复制大文件的方法Java 以尽可能快的方式复制大文件,java,multithreading,file-copying,filechannel,Java,Multithreading,File Copying,Filechannel,我试图找到一种以最快的方式复制大文件的方法 import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.util.ArrayList; public class FastFileCopy { public static void main(String[] args) { try { String from = "..
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
public class FastFileCopy {
public static void main(String[] args) {
try {
String from = "...";
String to = "...";
FileInputStream fis = new FileInputStream(from);
FileOutputStream fos = new FileOutputStream(to);
ArrayList<Transfer> transfers = new ArrayList<>();
long position = 0, estimate;
int count = 1024 * 64;
boolean lastChunk = false;
while (true) {
if (position + count < fis.getChannel().size()) {
transfers.add(new Transfer(fis, fos, position, position + count));
position += count + 1;
estimate = position + count;
if (estimate >= fis.getChannel().size()) {
lastChunk = true;
}
} else {
lastChunk = true;
}
if (lastChunk) {
transfers.add(new Transfer(fis, fos, position, fis.getChannel().size()));
break;
}
}
for (Transfer transfer : transfers) {
transfer.start();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
我测试了它,结果非常令人印象深刻。。。
但是有一个大问题,复制的文件比当前文件大很多
因此,请检查它并帮助我找到问题,谢谢:)这是一个XY问题。只需使用
Files.copy()
看看这对你来说是否不够快:
$ ls -lh ~/ubuntu-13.04-desktop-amd64.iso
-rw-rw-r-- 1 fge fge 785M Jul 12 2013 /home/fge/ubuntu-13.04-desktop-amd64.iso
$ cat Foo.java
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
public class Foo
{
public static void main(final String... args)
throws IOException
{
Files.copy(Paths.get("/home/fge/ubuntu-13.04-desktop-amd64.iso"),
Paths.get("/tmp/t.iso"), StandardCopyOption.REPLACE_EXISTING);
}
}
$ time java Foo
real 0m1.860s
user 0m0.077s
sys 0m0.648s
$ time java Foo
real 0m1.851s
user 0m0.101s
sys 0m0.598s
而且还可以更快。天知道为什么,Oracle不使用
sendfile(2)
,尽管这是Java 8,Linux 2.2已经存在了很长一段时间。由于每次循环都是按计数+1递增位置,然后使用`(fis、fos、position、position+count)进行传输,因此代码将创建如下传输对象:
new Transfer(fis, fos, 0,count)
new Transfer(fis, fos, count+1, 2count+1)
new Transfer(fis, fos, 2count+2, 3count+2)
new Transfer(fis, fos, 3count+3, 4count+3)
...
因此,尽管您将创建文件大小/count
传输类,但您要求传输的总字节数为(count+1)*(1+2+3+…)
此外,我认为FileChannel.TransferTo()
的工作方式与您认为的不同<代码>位置指定在源文件中开始读取的位置。它不指定在目标通道中写入的位置。因此,即使您获得了正确的大小,您最终也会得到正确大小的输出文件,但是内容将以线程写入它们的任何顺序混乱
您可以调用outChannel.position()
跳到正确的位置。我不清楚当多个线程以这种方式扩展文件大小时会发生什么样的混乱
实验是很好的,我鼓励您尝试一下并进行基准测试。然而,这些评论是正确的,即这种方法是错误的。只有一个磁盘,只有一个文件系统缓冲区作为后盾,让多个线程争夺它不会使它工作得更快,而且可能会使它工作得更慢 您不太可能在以下方面有所改进:
long count = 0;
long size = src.size();
while(count < size) {
count += src.transferTo(count, size - count, dest);
}
long count=0;
长尺寸=src.size();
while(计数<大小){
count+=src.transferTo(count,size-count,dest);
}
还要注意的是,很难对文件操作的性能做出判断,因为文件系统将缓存读写操作,所以您所做的很多操作都是在RAM上进行的超廉价操作
还要注意的是,至少在进行基准测试时,在考虑复制是否完成之前,您需要将已启动的所有线程
join()
。是否文件。复制(源、目标)
对您来说不够快?此外,如果文件位于单个硬盘驱动器上,则使用多个线程会降低性能。否:)。。。您可以用这种方法在20秒内复制3 GB。您是否至少尝试过文件。copy()
?撇开代码中的错误不谈,您认为多线程技术会使速度更快?你有多线程磁盘吗?可能是条带化的?线程不可能加速使用1%CPU的操作。在任何自尊的开发人员的机器上,该程序将文件缓存在内存中,并且在程序结束后,操作系统将写回脏的FS缓存。在程序流执行后添加时间同步,并添加时间。
long count = 0;
long size = src.size();
while(count < size) {
count += src.transferTo(count, size - count, dest);
}