如何在Streamlit中生成zip压缩包直接下载而不写入本地磁盘
解决方案
核心思路是用内存缓冲区替代本地文件存储,全程在内存中完成zip打包、编码流程,不会在服务端生成任何本地文件。
具体修改说明
- 引入
io.BytesIO作为zip文件的内存载体,代替原有本地文件路径传入ZipFile初始化参数 - 移除本地文件读写的相关逻辑,所有字节操作直接对内存缓冲区完成
- 原有文件名规则保持不变,依然取用户上传文件名的前缀追加
.zip作为下载文件名
修正后代码
import io import zipfile import base64 import streamlit as st import pandas as pd def downloader(list_df, datafile, file_type): # 提取上传文件的前缀名,保持命名规则不变 file_prefix = datafile.name.split(".")[0] zip_filename = f"{file_prefix}.zip" # 初始化内存字节流作为zip的存储载体 zip_buffer = io.BytesIO() # 直接在内存中生成zip文件,不会写入本地磁盘 with zipfile.ZipFile(zip_buffer, 'w', zipfile.ZIP_DEFLATED) as file_zip: for idx, df in enumerate(list_df): csv_filename = f"{file_prefix}_group_{idx}.csv" file_zip.writestr(csv_filename, pd.DataFrame(df).to_csv(index=False)) # 操作完成后将缓冲区指针移到起始位置,准备读取内容 zip_buffer.seek(0) # 直接从内存缓冲区读取字节做base64编码,不需要读本地文件 b64 = base64.b64encode(zip_buffer.read()).decode() href = f'<a href="data:application/zip;base64,{b64}" download="{zip_filename}">Click Here To Download</a>' st.markdown(href, unsafe_allow_html=True)
补充说明
- 代码里添加了
index=False参数导出CSV,避免默认把pandas的行索引也写入CSV文件,如果需要保留索引可以自行删除该参数 - 全程没有任何本地文件IO操作,打包生成的zip仅存在于服务端内存中,用户触发下载后内存会自动回收,不会残留本地文件
内容的提问来源于stack exchange,提问作者v_him
相关产品推荐
相关产品推荐

