streamlit 文件上传保存+预览
以下是一个使用 Streamlit
实现文件上传并保存到本地的示例代码,不限制文件大小:
import streamlit as st
# 设置页面标题
st.title('文件上传与保存示例')
# 文件上传
uploaded_file = st.file_uploader("请选择文件进行上传", type=None)
# 检查是否有文件上传
if uploaded_file is not None:
# 显示文件信息
st.write(f"文件名: {uploaded_file.name}")
st.write(f"文件大小: {uploaded_file.size} 字节")
# 获取文件字节内容
file_bytes = uploaded_file.read()
# 将文件保存到本地
save_path = f"./{uploaded_file.name}"
with open(save_path, "wb") as f:
f.write(file_bytes)
st.success(f"文件已保存到: {save_path}")
代码说明:
file_uploader
函数用于上传文件。type=None
表示不限制文件类型。- 通过
uploaded_file.read()
获取文件的字节内容。 - 使用
open
以写入二进制模式 (wb
) 将文件保存到本地。
这个示例没有限制文件大小,但要注意上传文件的最大尺寸可能受限于 Streamlit
默认设置或 Web 浏览器的限制。如果需要调整默认的最大上传大小,可以在 Streamlit 的配置文件(通常为 ~/.streamlit/config.toml
)中修改以下参数:
[server]
maxUploadSize = 2000
maxUploadSize
的单位是 MB。
为了优化文件传输的形式,可以考虑以下几个方面:
-
流式读取文件:
- 直接读取整个文件可能在文件较大时造成内存问题。可以通过分块读取文件(流式处理)来减少内存压力。
-
显示文件传输进度:
- 在文件上传过程中显示进度条,以提升用户体验。
-
减少内存占用:
- 避免一次性将整个文件读取到内存,按需处理文件。
基于这些优化思路,这里给出一个改进版代码:
import streamlit as st
import os
# 设置页面标题
st.title('文件上传与保存(流式传输)示例')
# 文件上传
uploaded_file = st.file_uploader("请选择文件进行上传", type=None)
if uploaded_file is not None:
# 显示文件信息
st.write(f"文件名: {uploaded_file.name}")
st.write(f"文件大小: {uploaded_file.size / (1024 * 1024):.2f} MB")
# 设定保存路径
save_path = f"./{uploaded_file.name}"
# 显示进度条
progress_bar = st.progress(0)
# 每次读取 1 MB 数据,防止大文件占用过多内存
chunk_size = 1024 * 1024 # 1MB
bytes_written = 0 # 已写入的字节数
# 打开文件并分块写入本地文件
with open(save_path, "wb") as f:
while True:
# 从上传的文件中按块读取数据
file_chunk = uploaded_file.read(chunk_size)
if not file_chunk:
break # 读取完成
# 写入到本地文件
f.write(file_chunk)
bytes_written += len(file_chunk)
# 更新进度条
progress_percent = bytes_written / uploaded_file.size
progress_bar.progress(progress_percent)
st.success(f"文件已成功保存到: {save_path}")
st.write(f"总写入字节数: {bytes_written}")
改进点:
-
流式读取:
- 使用
uploaded_file.read(chunk_size)
按 1MB 大小逐块读取文件,避免一次性读取整个文件造成内存压力。
- 使用
-
进度条:
- 通过
st.progress()
实现实时进度条,显示上传的进度,使用户体验更好。
- 通过
-
减少内存压力:
- 文件以流的形式逐块处理,而不是一次性加载到内存中,适合处理较大的文件。
注意事项:
Streamlit
本身并不支持后台异步处理,因此进度条只是本地写入的进度,在实际的 Web 环境中,上传进度也受到网络速度影响。
为了美化 Streamlit
的 file_uploader
组件并将界面配置为中文展示,可以通过以下方式来进行优化:
- 自定义上传按钮的提示:通过
label
参数自定义上传按钮的显示文本。 - 使用
Streamlit
内置的 Markdown 支持,美化界面。 - 配置 Streamlit 为中文显示:通过
streamlit/config.toml
文件进行语言配置。
优化代码:
import streamlit as st
# 设置页面标题
st.markdown(
"""
<h2 style='text-align: center; color: #FF6347;'>文件上传与保存</h2>
""",
unsafe_allow_html=True
)
# 文件上传
uploaded_file = st.file_uploader("请上传文件", type=None)
# 检查是否有文件上传
if uploaded_file is not None:
# 显示文件信息
st.markdown(f"**文件名:** {uploaded_file.name}")
st.markdown(f"**文件大小:** {uploaded_file.size / (1024 * 1024):.2f} MB")
# 设定保存路径
save_path = f"./{uploaded_file.name}"
# 显示进度条
progress_bar = st.progress(0)
# 每次读取 1 MB 数据
chunk_size = 1024 * 1024 # 1MB
bytes_written = 0 # 已写入的字节数
# 打开文件并分块写入本地文件
with open(save_path, "wb") as f:
while True:
# 从上传的文件中按块读取数据
file_chunk = uploaded_file.read(chunk_size)
if not file_chunk:
break # 读取完成
# 写入到本地文件
f.write(file_chunk)
bytes_written += len(file_chunk)
# 更新进度条
progress_percent = bytes_written / uploaded_file.size
progress_bar.progress(progress_percent)
st.success(f"文件已保存到: {save_path}")
st.markdown(f"**总写入字节数:** {bytes_written}")
美化与中文配置优化点:
-
标题美化:
使用st.markdown()
和 HTML 标记语言,使标题居中并自定义颜色(例如橙红色#FF6347
)。 -
自定义文本显示:
上传按钮的标签改为"请上传文件"
,并且上传后的文件信息(如文件名和大小)用加粗显示st.markdown()
。 -
进度条与用户反馈:
上传完成后会显示成功消息,并以加粗形式展示写入的字节数。
设置界面语言为中文:
如果你想要让 Streamlit
的界面内容(如按钮和系统提示)展示为中文,可以通过修改 Streamlit
配置文件实现。
-
打开或创建
~/.streamlit/config.toml
文件。 -
在文件中添加或修改以下内容:
[theme] primaryColor = "#FF6347" [language] default = "zh"
-
primaryColor
是用来配置主题颜色的,调整为与页面标题一致的橙红色。 -
language.default = "zh"
是用来将Streamlit
的界面显示设置为中文。
这样,Streamlit 界面的默认提示和按钮都会显示为中文,同时自定义的上传界面也会更加美观。
在 Streamlit
中展示多层文件夹结构,并支持文件预览,可以使用以下方法:
- 展示文件夹结构:通过递归遍历文件夹树,构建一个嵌套的目录结构。
- 文件预览:根据文件类型提供不同的预览方式,如文本文件的内容、图片的显示等。
下面是一个完整的示例代码:
import os
import streamlit as st
# 设置页面标题
st.title("文件夹与文件展示和预览")
# 获取文件夹路径
root_dir = st.text_input("请输入文件夹路径", value=".")
# 递归展示文件夹结构
def display_folder_structure(folder, level=0):
for item in os.listdir(folder):
item_path = os.path.join(folder, item)
if os.path.isdir(item_path):
# 显示文件夹名并递归显示其子文件夹
st.markdown(f"{' ' * level}📂 **{item}**")
display_folder_structure(item_path, level + 1)
else:
# 显示文件名并添加文件预览按钮
st.markdown(f"{' ' * level}📄 {item}")
with st.expander(f"预览 {item}"):
preview_file(item_path)
# 文件预览
def preview_file(file_path):
file_ext = os.path.splitext(file_path)[1].lower()
try:
if file_ext in [".txt", ".md", ".py", ".csv"]: # 文本文件
with open(file_path, "r", encoding="utf-8") as f:
st.text(f.read())
elif file_ext in [".jpg", ".jpeg", ".png", ".gif"]: # 图片文件
st.image(file_path)
elif file_ext in [".mp4", ".avi", ".mov"]: # 视频文件
st.video(file_path)
elif file_ext in [".mp3", ".wav"]: # 音频文件
st.audio(file_path)
else:
st.warning("不支持的文件类型预览")
except Exception as e:
st.error(f"无法预览文件:{str(e)}")
# 显示文件夹结构
if os.path.isdir(root_dir):
display_folder_structure(root_dir)
else:
st.error("文件夹路径无效,请重新输入。")
代码说明:
-
输入文件夹路径:
- 使用
st.text_input
让用户输入需要展示的根文件夹路径。
- 使用
-
递归显示文件夹结构:
display_folder_structure()
函数递归遍历指定文件夹,并通过缩进表示层级关系。- 对于每个文件,使用
st.expander
提供文件预览功能,点击展开后才显示文件内容。
-
文件预览功能:
preview_file()
函数根据文件扩展名进行预览。- 文本文件(
.txt
、.md
、.py
、.csv
):直接读取并显示文件内容。 - 图片文件(
.jpg
、.png
、.gif
):使用st.image()
显示图片。 - 视频文件(
.mp4
、.avi
、.mov
):使用st.video()
显示视频。 - 音频文件(
.mp3
、.wav
):使用st.audio()
播放音频。
- 文本文件(
- 如果文件格式不支持,会显示警告提示。
-
错误处理:
- 添加了对异常的捕获,防止读取或预览文件时出现问题,避免程序崩溃。
功能扩展:
- 文件过滤:可以根据需要修改代码以过滤出特定类型的文件(如只显示文本文件或图片)。
- 文件操作:可以扩展功能,添加文件下载、删除等操作。
为了优化大文件的预览体验,可以实现滚动加载,即用户滚动时逐步加载文件内容,而不是一次性读取整个文件。这种方式可以有效防止大文件占用过多内存和加载时间。
以下是一个优化后的代码,支持滚动加载文本文件的内容:
优化代码:
import os
import streamlit as st
# 设置页面标题
st.title("文件夹与文件展示和预览(支持滚动加载)")
# 获取文件夹路径
root_dir = st.text_input("请输入文件夹路径", value=".")
# 递归展示文件夹结构
def display_folder_structure(folder, level=0):
for item in os.listdir(folder):
item_path = os.path.join(folder, item)
if os.path.isdir(item_path):
# 显示文件夹名并递归显示其子文件夹
st.markdown(f"{' ' * level}📂 **{item}**")
display_folder_structure(item_path, level + 1)
else:
# 显示文件名并添加文件预览按钮
st.markdown(f"{' ' * level}📄 {item}")
with st.expander(f"预览 {item}"):
preview_file(item_path)
# 文件预览(支持滚动加载)
def preview_file(file_path):
file_ext = os.path.splitext(file_path)[1].lower()
try:
if file_ext in [".txt", ".md", ".py", ".csv"]: # 文本文件滚动加载
load_text_file_with_scroll(file_path)
elif file_ext in [".jpg", ".jpeg", ".png", ".gif"]: # 图片文件
st.image(file_path)
elif file_ext in [".mp4", ".avi", ".mov"]: # 视频文件
st.video(file_path)
elif file_ext in [".mp3", ".wav"]: # 音频文件
st.audio(file_path)
else:
st.warning("不支持的文件类型预览")
except Exception as e:
st.error(f"无法预览文件:{str(e)}")
# 滚动加载文本文件
def load_text_file_with_scroll(file_path):
"""支持滚动加载的文本文件预览"""
CHUNK_SIZE = 1000 # 每次加载的字符数
with open(file_path, "r", encoding="utf-8") as f:
# 初始化状态,保存已经加载的内容
if 'file_offset' not in st.session_state:
st.session_state.file_offset = 0
st.session_state.file_chunk = ""
# 读取当前文件块
f.seek(st.session_state.file_offset)
chunk = f.read(CHUNK_SIZE)
st.session_state.file_chunk += chunk
st.session_state.file_offset = f.tell()
# 显示当前已加载的内容
st.text(st.session_state.file_chunk)
# 如果没有加载完全部文件,显示“加载更多”按钮
if chunk:
if st.button("加载更多"):
load_text_file_with_scroll(file_path)
else:
st.info("文件已完全加载")
# 显示文件夹结构
if os.path.isdir(root_dir):
display_folder_structure(root_dir)
else:
st.error("文件夹路径无效,请重新输入。")
代码优化点:
-
滚动加载大文本文件:
- 使用
st.session_state
记录当前已经读取的文件偏移量(file_offset
)和已读取的文本(file_chunk
)。 - 每次点击“加载更多”按钮时,继续从上次读取位置加载更多的文本(
CHUNK_SIZE = 1000
)。 - 每次加载一部分内容,逐步显示,避免一次性加载整个文件。
- 使用
-
状态保持:
st.session_state
用于保持文件读取的进度,确保用户可以分段预览大文件。
-
“加载更多”按钮:
- 当文件内容未完全加载时,显示“加载更多”按钮,用户点击后继续加载剩余部分。文件加载完毕时,显示“文件已完全加载”的提示。
工作流程:
- 当用户点击预览文本文件时,文件会按
CHUNK_SIZE
(如 1000 字符)逐块加载到页面中。 - 页面每次只加载一小部分文本内容,用户可以通过点击“加载更多”按钮来逐步显示剩余部分,直到文件完全加载。
优势:
- 减少内存占用:逐步读取文件内容,避免一次性加载大文件。
- 提升用户体验:大文件可快速开始预览,用户可以自主选择是否继续加载。
可扩展性:
- 支持更多文件类型:可以扩展
load_text_file_with_scroll()
函数,使其支持其他类型的文件(如 JSON 文件等)。 - 更灵活的滚动控制:可以根据需要调整每次加载的块大小(
CHUNK_SIZE
),或添加滑动条控制。