You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于shutil、Flask与JavaScript实现归档创建时同步下载

解决方案:流式生成Zip并实时响应下载

你的核心问题是shutil.make_archive会先生成完整归档文件再返回,导致前端需要等待过长时间。解决思路是直接在响应中流式生成Zip文件,让前端立即开始下载,同时后台边读取外接硬盘文件边打包,无需等待整个归档完成。

1. 修改Flask后端代码

替换原有的/archive路由,新增一个直接流式下载文件夹的接口,用zipfile配合内存缓冲区分块生成Zip内容,避免提前占用硬盘空间或内存溢出:

import os
import io
import zipfile
from flask import Flask, request, Response, send_file

app = Flask(__name__)
drive = "/path/to/your/external/drive/"  # 替换为你的外接硬盘根路径
# 无需再提前创建归档文件夹,流式输出不依赖本地存储

def stream_zip(folder_path):
    buffer = io.BytesIO()
    # 初始化Zip文件对象,使用压缩模式
    with zipfile.ZipFile(buffer, 'w', zipfile.ZIP_DEFLATED) as zipf:
        # 遍历目标文件夹下的所有文件
        for root, _, files in os.walk(folder_path):
            for file in files:
                file_full_path = os.path.join(root, file)
                # 计算文件在Zip中的相对路径(避免保留完整硬盘路径)
                zip_inner_path = os.path.relpath(file_full_path, folder_path)
                
                # 分块读取外接硬盘文件并写入Zip
                with open(file_full_path, 'rb') as f:
                    zipf.writestr(zip_inner_path, f.read())
                
                # 将缓冲区内容输出给前端,之后重置缓冲区
                buffer.seek(0)
                yield buffer.read()
                buffer.seek(0)
                buffer.truncate()
    # 输出Zip文件的结尾标识
    buffer.seek(0)
    yield buffer.read()

@app.route('/download-folder')
def download_folder():
    target_path = request.args.get('path')
    zip_name = request.args.get('name')
    folder_full_path = os.path.join(drive, target_path)
    
    # 校验目标路径是否为有效文件夹
    if not os.path.isdir(folder_full_path):
        return "目标文件夹不存在", 404
    
    # 设置响应头,告诉浏览器处理下载动作
    headers = {
        'Content-Type': 'application/zip',
        'Content-Disposition': f'attachment; filename="{zip_name}.zip"'
    }
    
    # 返回流式响应,前端会立即开始接收数据
    return Response(stream_zip(folder_full_path), headers=headers)

# 保留原有的单个文件下载接口
@app.route('/download')
def download_file():
    file_path = request.args.get('path')
    full_path = os.path.join(drive, file_path)
    if not os.path.isfile(full_path):
        return "目标文件不存在", 404
    return send_file(full_path, as_attachment=True)

2. 修改前端JavaScript代码

无需再等待归档接口返回结果,直接判断文件类型并触发对应下载接口,同时对路径参数做编码处理避免特殊字符报错:

function download_file() {
    let downloadUrl;
    // 判断当前路径是否为文件夹(无后缀名)
    if (!path.includes('.')) {
        // 文件夹调用流式下载接口
        downloadUrl = `/download-folder?path=${encodeURIComponent(path)}&name=${encodeURIComponent(select)}`;
    } else {
        // 单个文件调用原有下载接口
        downloadUrl = `/download?path=${encodeURIComponent(path)}`;
    }
    const downloader = document.createElement('a');
    downloader.href = downloadUrl;
    downloader.click();
}

关键细节说明

  • 实时下载:通过Flask的Response配合生成器函数,每打包一个文件就立即将内容发送给前端,浏览器会实时开始下载,无需等待整个Zip生成完毕。
  • 资源优化:用内存缓冲区分块处理文件,避免一次性加载大文件到内存,适配老旧外接硬盘的低速读取特性。
  • 路径安全:使用encodeURIComponent编码路径参数,避免空格、特殊字符导致的请求异常。

内容的提问来源于stack exchange,提问作者Werner van der Merwe

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 17:28:33