php 如何在O(n)时间内将多个文件添加到ZipArchive

vatpfxk5  于 2023-10-15  发布在  PHP
关注(0)|答案(2)|浏览(120)

**已关闭。**此问题需要debugging details。它目前不接受回答。

编辑问题以包括desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem。这将帮助其他人回答这个问题。
7小时前关闭
Improve this question
我提供了一种下载多张照片作为一个单一的存档文件的方法。
TAR格式工作正常,但大多数人没有任何东西可以打开TAR文件在他们的设备上,然后抱怨它不工作。
ZIP格式是不必要的(因为照片已经压缩),但大多数人都可以打开。
内置的PHP类ZipArchive似乎只有一个方法addFile来一次添加一个文件。这似乎涉及到整个存档的解压缩和重新压缩,其效果是您添加的文件越多,它就越慢-即。它在O(n2)时间内运行以添加n个文件。超过30-40张高分辨率照片的影响就变得灾难性了。
我是不是错过了什么ZipArchive?或者这是类中的一个缺点,应该作为特性请求提出来?
是否有其他方法可以实现快速生成存档格式的目标,使大多数人能够在不安装其他软件的情况下打开存档格式?

yqkkidmi

yqkkidmi1#

如果是这样的话,这将是一个相当有缺陷的设计,但你永远不知道,所以让我们测试一下。
首先,让我们准备一些50 MB的文件,以便在其余的基准测试中使用:

define('FILE_COUNT', 100);
mkdir(__DIR__ . '/data');
for ($i =0; $i < FILE_COUNT; $i++) {
    file_put_contents(__DIR__ . "/data/file-$i.txt", str_repeat('x', 52_428_800));
}

现在,让我们创建一些ZIP压缩文件,增加文件数量:

define('FILE_COUNT', 1); // <-------- We'll be increasing this

$t0 = microtime(true);

$zip = new ZipArchive();
$zip->open(__DIR__ . '/zip-test.zip', ZipArchive::CREATE);
for ($i = 0; $i < FILE_COUNT; $i++ ){
    $zip->addFile(__DIR__ . "/data/file-$i.txt");
}
echo "Files added: {$zip->numFiles}\n";
echo "Status: {$zip->status}\n";
$zip->close();

$time = microtime(true) - $t0;
echo "Total time: " . number_format($time, 3) . " seconds\n";
echo "Average time: " . number_format($time / FILE_COUNT, 3) . " seconds/file\n";
echo "Max RAM used: " . number_format(memory_get_peak_usage(real_usage: true)) . " bytes\n";

在我当前的计算机(Windows 10桌面,PHP/8.1.15 64位)中:

Files added: 1
Status: 0
Total time: 0.505 seconds
Average time: 0.505 seconds/file
Max RAM used: 2,097,152 bytes
Files added: 10
Status: 0
Total time: 4.854 seconds
Average time: 0.485 seconds/file
Max RAM used: 2,097,152 bytes
Files added: 100
Status: 0
Total time: 48.428 seconds
Average time: 0.484 seconds/file
Max RAM used: 2,097,152 bytes

所以......这当然不是一个科学的基准,只是一个快速的测试,以弄清楚整体情况。结论是,它看起来是线性的,并且每次都不会压缩和解压缩整个存档。实际上,大的延迟发生在$zip->close()之间。
然后我运行了一些完全禁用压缩的测试:

for ($i = 0; $i < FILE_COUNT; $i++ ){
    $zip->addFile(__DIR__ . "/data/file-$i.txt");
    $zip->setCompressionName(__DIR__ . "/data/file-$i.txt", ZipArchive::CM_STORE);
}

实际上更快:

Files added: 100
Status: 0
Total time: 19.541 seconds
Average time: 0.195 seconds/file
Max RAM used: 2,097,152 bytes

最后但并非最不重要的是,在我的第一次测试中,我没有过多考虑就使用了->addFromString(),我发现随着我添加更多文件,RAM的使用率一直在增加。
结论:

  • 时间复杂度O(n)
  • 如果您的文件已被压缩,请禁用压缩。
  • 让ZipArchive尽可能从磁盘加载文件。
yqlxgs2m

yqlxgs2m2#

关于ZipArchive::addFile手册中的注解,看起来该文件实际上并没有添加到函数调用中。文件将在zip对象关闭时添加。

相关问题