如何创建下载含指定图片列表的ZIP文件 修复路径嵌套与图片存储问题
问题根因
原代码存在三个核心问题:
- 写入文件时直接将URL字符串作为内容存储,没有发起HTTP请求拉取URL对应的图片二进制数据,最终压缩包内的文件只有URL文本,不存在实际图片内容。
- 调用
zip_file.write()时仅传入了文件的本地绝对路径,zip模块默认会将完整路径结构全部打包进压缩包,最终解压就会出现多层嵌套的冗余目录。 - 错误使用
StringIO存储二进制格式的zip内容,存在压缩包损坏的风险,二进制数据应该使用BytesIO作为缓冲区。 - 本地临时目录的逻辑完全多余,会产生不必要的磁盘IO和临时文件残留问题。
最优修复方案
不需要在服务端创建本地临时文件夹,所有图片拉取、zip打包操作全在内存中完成,性能更高也没有文件残留问题,修正后代码如下:
import requests import zipfile from io import BytesIO from django.http import HttpResponse def download_image_zip(request): image_list = ['https://example.com/media/file1.jpg', 'https://example.com/media/file2.jpg'] # 初始化内存二进制缓冲区 buffer = BytesIO() # 压缩时启用DEFLATED算法减小zip体积 with zipfile.ZipFile(buffer, "w", zipfile.ZIP_DEFLATED) as zip_file: for idx, img_url in enumerate(image_list): # 拉取图片实际二进制内容 img_resp = requests.get(img_url, timeout=10) # 请求失败直接抛出异常,避免写入无效内容 img_resp.raise_for_status() # 从URL中截取原始文件名 file_name = img_url.rsplit("/", 1)[-1] # 指定文件在zip包内的存储路径,统一放在img目录下 zip_inner_path = f"img/{file_name}" # 直接将图片内容写入zip,无需落盘 zip_file.writestr(zip_inner_path, img_resp.content) # 将指针移到缓冲区起始位置 buffer.seek(0) resp = HttpResponse(buffer.getvalue(), content_type="application/x-zip-compressed") resp['Content-Disposition'] = 'attachment; filename=gik.zip' return resp
运行以上代码生成的zip包,解压后结构完全符合预期:
gik/ └── img/ ├── file1.jpg └── file2.jpg
保留本地临时文件的修改方式
如果因为特殊业务要求必须先把图片存到本地临时目录再打包,只需要修改两处逻辑即可:
- 写本地文件时先拉取图片二进制内容,不要直接写入URL字符串,同时给文件加上对应图片后缀,避免解压后系统无法识别文件格式
- 写入zip时通过
arcname参数指定文件在压缩包内的相对路径,过滤掉本地绝对路径
核心修改片段:
# 拉取图片写入本地目录的修正逻辑 for i, img_url in enumerate(image_list): img_resp = requests.get(img_url, timeout=10) img_resp.raise_for_status() # 提取文件后缀 suffix = img_url.rsplit(".", 1)[-1] save_path = os.path.join(folder, f"{i}.{suffix}") with open(save_path, 'wb') as f: f.write(img_resp.content) # 写入zip的修正逻辑 for filename in os.listdir(folder): file_abs_path = os.path.join(folder, filename) # arcname指定压缩包内的相对路径,不会带入本地绝对路径 zip_file.write(file_abs_path, arcname=f"img/{filename}")
内容的提问来源于stack exchange,提问作者D_P
相关产品推荐
相关产品推荐

