在PHP中复制大文件(超过2GB)

15

我需要通过PHP复制一个大文件(6 GB),该如何做呢?Copy()函数无法实现。

我正在使用 PHP 5.3 在 Windows 32/64 上。


3
为什么 copy 做不到这一点?你是否收到错误消息? - Gordon
复制到哪里?目标文件系统支持6GB的文件吗? - Lightness Races in Orbit
我认为PHP有一些限制(> 2 GB)http://www.php.net/manual/en/function.copy.php#69001 copy()仅从文件中获取几MB,没有错误。filesize()也存在问题...是的,目标文件系统是NTFS。 - Bauer01
@Gordon 因为即使在64位系统上,PHP的64位版本中的copy()函数似乎在每4 GiB后都会将内部偏移位置重置为0。 - StanE
1
@StanE,这似乎与文件系统有关。请参见https://bugs.php.net/bug.php?id=81145。 - Gordon
6个回答

23

这应该可以做到。

function chunked_copy($from, $to) {
    # 1 meg at a time, you can adjust this.
    $buffer_size = 1048576; 
    $ret = 0;
    $fin = fopen($from, "rb");
    $fout = fopen($to, "w");
    while(!feof($fin)) {
        $ret += fwrite($fout, fread($fin, $buffer_size));
    }
    fclose($fin);
    fclose($fout);
    return $ret; # return number of bytes written
}

如果$from是一个url,那么你的缓冲区大小被限制在8k,这使得这个过程变得低效。 - TomTerrific
由于某种原因,它在复制整个文件之前就结束了。 - Flash Thunder

2

1
除非您的脚本执行立即停止,否则您应该在此之后关闭这些。 - Ciaran McNulty
我在一台64位Windows 10构建上尝试了这个,使用的是PHP 8.0.7的64位版本。stream_copy_to_stream()似乎在文件大小超过4 GiB时存在相同的问题。每4 GiB后,文件内容会重复。 - StanE

2

最近版本的PHP使用分块复制文件,因此您可以安全地使用php copy() 函数


2
这里的“recent”是什么意思?如果有一个版本号会更好。 - ftrotter
不,我认为这是不正确的。我正在使用编译为64位的PHP 8.0.7(因此它在内部使用8字节整数)。copy()仍然不支持复制大于4 GiB的文件。它确实会复制它们,但每4 GiB后它都会从偏移量0开始写入。 - StanE
PHP 8.1.9在使用copy()复制4GB文件时卡在了2.7GB。 - Flash Thunder

1

如果是 Linux 机器,您可以使用 exec()

$srcFile = escapeshellarg($pathToSrcFile);
$trgFile = escapeshellarg($pathToTrgFile);

exec("cp $srcFile $trgFile");

1
我更喜欢 PHP 的方式,如果可能的话,虽然也可以在 Windows 上工作。 - Bauer01
1
@Adrian 是的,但是你需要使用“copy”命令,而不是“cp”。 - RReverser
真的,我假设这是理解的。 - Adrian World
1
说实话,从所有的答案中,这是唯一一个合理的。 - Karoly Horvath
1
因为我的应用程序是设计为 Nette PHP 框架的一个组件 - 它是一个简单的文件管理器,我希望在服务器上禁用 exec 使用时有一个解决方法。分块复制是我认为最好的解决方案。 - Bauer01
显示剩余3条评论

1

我会逐个 X 字节地复制它(每次迭代几兆字节)。 X 将是最优化的大小,这取决于您的机器。 而且我不会通过 Web 服务器进行操作,而是作为独立脚本运行,通过 cron 或一次性调用它(cli)。


0
如果你想从一个服务器复制文件到另一个服务器,并且两个服务器都有ftp访问权限,那么你可以在源系统上简单地使用ftp 'put'命令将大文件发送到另一个系统。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接