[关闭]
@Chiang 2020-08-09T18:32:39.000000Z 字数 2729 阅读 736

PHP文件打包(Zip)

2020-08 工作总结


ZipArchive::addFile

  • ZipArchive::addFile — Adds a file to a ZIP archive from the given path

ZipArchive::addFromString

  • ZipArchive::addFromString — Add a file to a ZIP archive using its contents

业务场景举例(这只是个伪代码,目的是实现代码逻辑)

  1. $zip = new ZipArchive();
  2. $filename = "./test112.zip";
  3. if ($zip->open($filename, ZipArchive::CREATE)!==TRUE) {
  4. exit("cannot open <$filename>\n");
  5. }
  6. dirToArray($dir, $zip, $zipdir);
  7. echo "numfiles: " . $zip->numFiles . "\n";
  8. echo "status:" . $zip->status . "\n";
  9. $zip->close();
  10. //读取文件
  11. function dirToArray($dir, $zip, $zipdir) {
  12. $result = array();
  13. $cdir = scandir($dir);
  14. foreach ($cdir as $key => $value)
  15. {
  16. if (!in_array($value,array(".","..")))
  17. {
  18. if (is_dir($dir . DIRECTORY_SEPARATOR . $value))
  19. {
  20. $result[$value] = dirToArray($dir . DIRECTORY_SEPARATOR . $value, $zip);
  21. }
  22. else
  23. {
  24. $contents = file_get_contents( $path );
  25. $zip->addFromString($zipEntryName, $contents);
  26. $zip->addFile($zipdir . $value);
  27. }
  28. }
  29. }
  30. return $result;
  31. }

核心代码

  1. $contents = file_get_contents( $path );
  2. $zip->addFromString($zipEntryName, $contents);
  3. $zip->addFile($zipdir . $value);

addFromStringaddFile 都是把 文件夹里的文件压缩到指定压缩文件中.
区别是:

  • addFromString 先通过 file_get_contents 函数先把文件内容一次性都读到内存中,然后添加到压缩文件中
  • addFile 是直接根据文件路径(文件名,文件句柄)添加到压缩文件

存在的问题

单个文件很大的情况

file_get_contents 函数容易内存溢出,这样addFromString 方法就不好用了,可以使用 addFile 方法

addFile 方法,在内存耗尽之前,您将用完文件ID.它实际上不需要很多内存,只使用文件名和文件处理程序.

如果非要使用addFromString方法,这里就要想办法PHP读取大文件的解决方案

文件数量很多的情况(文件夹下有11221个文件)

  • 当然在文件数量很多的情况下addFile 方法 会出现一个问题
  • Maybe I need to explain this problem a little more.
    I am trying to archive a folder on the server, at the moment it contains 5609 folders and 11,221 files. The script loops through the files adding them to the archive using the addFile() method. After the first 1002 files I get a ZIPARCHIVE::ER_OPEN. If I close the archive and the open it again I still have that error. However, if I close the archive and open it before I get that error then I can archive all 11,221 files.
    Since closing the file and re-opening fixes the problem (so long as I do that before I get the error) Then may I suggest that closing an archive will clear the status. Obviously, it would be good if this wasn't necessary, in thatthe code could catch the problem and allocate extra file handles if that is the problem.
  • "it would be good if this wasn't necessary, in thatthe code could catch the problem and allocate extra file handles if that is the problem."
    This is not something I can control. The operating system defines it and there is no way for me to increase this value.
    I suggest you to close and reopen it every 1000 or so (or even 255 if you want to go on the safest way, ie old windows).
    Future releases will have a different mode, where the checks will done only when you close the archives.

总结

  • file_get_contents 在大文件的场景下会出现内存溢出的问题,这里可以参考PHP 读取超大文件的方法

  • addFile 在多文件情况下会超出文件个数限制(1024 or 256),最好在没有达到上限的条件下 调用 $zip->close() 方法先压缩一部分,这样循环,感觉类似于队列的思想,人为程序设置上限


参考资料:
Zip
ZipArchive::addFromString
ZipArchive::addFile
file_get_contents
Memory problem with ZipArchive::addFile
addFile() leaks file handles

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注