我用的是 php ,问了一圈 AI ,告诉我使用 ZipStream ,但是我试了同样需要等待压缩的时候非常久,而不是像群晖 NAS 那样,立即开始下载,且浏览器不显示最终文件大小。 请问 v 友这是如何做到的
public function downloadFolderNew() { $path = $this->request->param("path", ""); if (!empty($path)) { // 将路径转换为项目的公共路径 $path = str_replace("D:\\phpproject\\test\\public\\", public_path(), $path); } if (!is_dir($path)) { $this->error("路径不存在"); } $fileName = $this->request->param("file_name", "") ?: uniqid(); $zipFileName = $fileName . ".zip"; // 设置响应头 header('Content-Type: application/zip'); header('Content-Disposition: attachment; filename="' . $zipFileName . '"'); header('X-Accel-Buffering: no'); // 关闭 Nginx 的输出缓冲 // 禁用输出缓冲区 if (ob_get_level()) { ob_end_clean(); } // 立即输出部分内容,浏览器开始下载 echo "\xEF\xBB\xBF"; // 避免 PHP 输出缓冲,立即开始下载 flush(); // 创建一个 ZIP 流 $zip = new ZipStream\ZipStream(null, [ 'outputStream' => 'php://output' // 将输出直接定向到浏览器 ]); // 递归添加文件夹内容到 ZIP $this->addFolderToZip($zip, $path, ''); // 结束 ZIP 流 $zip->finish(); exit(); } private function addFolderToZip($zip, $folder, $zipPath) { // 创建迭代器,遍历文件夹中的文件 $files = new \RecursiveIteratorIterator( new \RecursiveDirectoryIterator($folder, \RecursiveDirectoryIterator::SKIP_DOTS), \RecursiveIteratorIterator::LEAVES_ONLY ); foreach ($files as $file) { $filePath = $file->getRealPath(); $relativePath = substr($filePath, strlen($folder) + 1); // 获取文件相对路径 if (!$file->isDir()) { // 确保文件路径和内容正确添加到 ZIP 中 $zip->addFileFromPath($zipPath . $relativePath, $filePath); } // 刷新输出缓冲,逐步发送数据到浏览器 flush(); } }
![]() | 1 kele1997 2024-09-11 17:23:25 +08:00 |
2 dode 2024-09-11 17:25:31 +08:00 流式处理,把 zip 的输出流设置为浏览器的输入流 |
3 ntedshen 2024-09-11 17:36:07 +08:00 不看注释都知道是 nginx 用户。。。 因为我写 php 的时候也没搞定那个疑似是缓存的缓存问题。。。。。。。。。。。。。。。。 群晖没测过。。。 mega 点击下载 zip 文件以后是前端分片下载单个文件然后前端自己打包的。。。 我现在自己写 nas 也是造 mega 造的。。。 |
4 okakuyang 2024-09-11 19:22:13 +08:00 因为 zip 的文件格式特性,应该是可以是实现一边压缩一边传输的。由于压缩还在进行中,程序还没有计算出最后的文件大小,所以不会开始就告诉浏览器文件大小。 |
![]() | 5 zhuangzhuang1988 java 的话有个 netty 中间插入个中间层就可以了 https://netty.io/4.1/xref/io/netty/handler/codec/http/HttpContentEncoder.html#L194 |
7 billccn 2024-09-12 02:56:01 +08:00 你把 CompressionMethod 设置成 STORE (就是不压缩)试试?或者把 defaultDeflateLevel 调整一下。 另外显示的大小是在 HTTP 头里的,你不提前算好所有文件+zip 开销,等 HTTP 头都发完了才开始遍历目录那肯定不会有大小的。 |
8 leonshaw 2024-09-12 09:42:46 +08:00 via Android 有没有办法续传呢 |
9 sunchuo 2024-09-12 10:54:56 +08:00 |
10 okakuyang 2024-09-12 11:01:19 +08:00 @wxf666 额,不是很了解 gzip 的机制,但是估计和 zip 差不多是把单个文件进行压缩,zip 设置成打包不压缩,理论上会很快生成 zip 文件,然后传输给 gzip ,感觉不是很靠谱。 |
![]() | 11 siweipancc 2024-09-13 08:42:35 +08:00 via iPhone 206 请求+队列+二进制合并 |
![]() | 12 siweipancc 2024-09-13 08:44:40 +08:00 via iPhone 需要有自定义下载条,建议楼主参考下 asmr.one 的实现。 |