使用PHP PCL Zip分多次压缩单个大文件

4

100 MB的文件 --> 10个ZIP调用(每次10 MB的zip) --> 1个ZIP文件

如果我要将一个100 MB的文件添加到Zip文件中(每次压缩10 MB),我需要发起10个调用。

问题在于,我们的系统有内存和时间限制(每次调用最多处理10到15MB)。

因此,使用多个调用对大文件进行压缩是基本思路。

如有需要,我可以提供更多数据。


你到底想要问什么? - Sid
将一个大文件(比如100MB)压缩成多个小文件,以适应内存限制较低的系统,可以使用10个PHP调用来完成。 - itsoft3g
你尝试过使用PHP内部的系统调用来实现吗?还是使用了PHP的zip函数? - Hawili
2个回答

3

你曾经尝试过PECL Zip吗?

使用以下代码压缩两个文件,没有任何内存限制问题。时间限制可能会重置。我的环境:内存限制为3MB,最大执行时间为20秒。

<?php
set_time_limit(0);
$zip = new ZipArchive();
$zip->open('./test.zip', ZipArchive::CREATE);
$zip->addFile('./testa'); // 1.3 GB
$zip->addFile('./testb'); // 700mb
$zip->close();
注意: set_time_limit() 在php < 5.4并且save_mode=on的情况下无法使用。
另一种方法是在后台进程中创建zip文件。这可以避免可能出现的memory_limit问题。
以下是一个例子:http://pastebin.com/7jBaPedb 用法:
try {
  $t = new zip('/bin', '/tmp/test.zip');
  $t->zip();

  if ($t->waitForFinish(100))
    echo "Succes :)";
  else
    echo $t->getOutput();
} catch ($e) {
  echo $e->getMessage();
}

不必等到进程结束,您可以将pid写入数据库,如果进程已经完成,则提供文件...


我正在寻找一个解决方案,即使在任何共享主机中也能正常工作。您应用的3MB限制可能无法起作用,因为我觉得使用3MB内存压缩1.3GB是不可能的。请注意,Web服务器(如Apache)也会有内存和时间限制。根据共享主机的限制,您无法获取pid。 - itsoft3g
@itsoft3g 请尝试上面的示例。它能很好地工作。在发布这篇文章之前,我已经测试了代码。PECL Zip正是您所需的(以块读写文件,不会影响内存限制)。 - jgb
但是我有时间限制,所以我想分多次完成。 - itsoft3g

2
阅读您的问题后,我首先开始创建一个分块压缩器,以完成您所要求的任务。它会生成一个包含到网页的链接数组,您需要按顺序打开这些链接来创建一个zip文件。虽然这个想法是可行的,但我很快意识到并不真正需要这么做。
只有当打包程序尝试一次性打开整个文件并进行压缩时,内存限制才会成为问题。幸运的是,已经有一些聪明的人发现按块处理更容易。
Asbjorn Grandt是那些创建了这个zip类的人之一,它非常易于使用并且能够满足您的需求。
首先,我创建了一个非常大的文件。它将达到500MB,并包含各种字母。这个文件一次性处理太慢,结果导致了致命的内存限制错误。
<?php
$fh = fopen("largefile.txt", 'w');
fclose($fh);
$fh = fopen("largefile.txt", 'ab');
$size = 500;
while($size--) {
  $l = chr(rand(97, 122));
  fwrite($fh, str_repeat($l, 1024*1024));
}
fclose($fh);
?>

要使用zip类,我们需要执行以下操作:

<?php
include('zip.php');

$zip = new Zip();
$zip->setZipFile("largefile.zip");
//the firstname is the name as it will appear inside the zip and the second is the filelocation. In my case I used the same, but you could rename the file inside the zip easily.
$zip->addLargeFile("largefile.txt", "largefile.txt");
$zip->finalize();
?>

现在,在我的服务器上创建一个大的zip文件只需要几秒钟,结果是一个550KB的文件。

如果由于某种奇怪的原因,您仍然需要在多个网络请求中执行此操作,请告诉我。我仍然拥有最初用于执行此操作的代码。


非常抱歉耽搁了这么久。你应该压缩了一个500MB的文本文件,所以你得到的是大约550KB(压缩文件)。因此,这应该需要很少的时间。我想要它在几个Web请求中,并且也尝试一些500MB的媒体文件(可能是电影)。 - itsoft3g

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