Flask 文件和文件夹下载服务实现
以下是一个基于 Flask 框架的简单 Web 服务,用于开放指定文件夹(./shared_files
),允许用户通过浏览器浏览和下载文件夹中的所有文件和子文件夹。ZIP 和 TAR 文件将直接下载,而文件夹将以 ZIP 格式下载。
代码实现
from flask import Flask, send_file, abort, render_template_string, Response
import os
import zipfile
import io
app = Flask(__name__)
# 指定要开放的文件夹路径
SHARED_FOLDER = "./shared_files"
# 确保文件夹存在
if not os.path.exists(SHARED_FOLDER):
os.makedirs(SHARED_FOLDER)
# HTML 模板,显示文件和文件夹列表
HTML_TEMPLATE = """
<!DOCTYPE html>
<html>
<head>
<title>文件和文件夹下载</title>
<style>
body { font-family: Arial, sans-serif; margin: 20px; }
h1 { color: #333; }
ul { list-style: none; padding: 0; }
li { margin: 10px 0; }
a { text-decoration: none; color: #0066cc; }
a:hover { text-decoration: underline; }
.folder { font-weight: bold; color: #660099; }
</style>
</head>
<body>
<h1>共享文件夹中的内容</h1>
<ul>
{% for item, is_folder in items %}
<li class="{% if is_folder %}folder{% endif %}">
<a href="{% if is_folder %}/download_folder/{{ item }}{% else %}/download_file/{{ item }}{% endif %}">
{{ item }}{% if is_folder %} (文件夹){% else %} (文件){% endif %}
</a>
</li>
{% endfor %}
</ul>
</body>
</html>
"""
@app.route('/')
def list_contents():
try:
# 获取文件夹中的文件和子文件夹
items = []
for entry in os.listdir(SHARED_FOLDER):
full_path = os.path.join(SHARED_FOLDER, entry)
is_folder = os.path.isdir(full_path)
items.append((entry, is_folder))
return render_template_string(HTML_TEMPLATE, items=items)
except Exception as e:
return f"错误: 无法读取文件夹 - {str(e)}", 500
@app.route('/download_file/<path:filename>')
def download_file(filename):
file_path = os.path.join(SHARED_FOLDER, filename)
# 安全检查:确保文件存在且在共享文件夹内
if os.path.isfile(file_path) and os.path.abspath(file_path).startswith(os.path.abspath(SHARED_FOLDER)):
try:
# 直接下载文件,包括 ZIP 和 TAR,不做任何处理
return send_file(file_path, as_attachment=True)
except Exception as e:
abort(500, f"错误: 无法下载文件 - {str(e)}")
else:
abort(404, "文件不存在或无权访问")
@app.route('/download_folder/<path:foldername>')
def download_folder(foldername):
folder_path = os.path.join(SHARED_FOLDER, foldername)
# 安全检查:确保文件夹存在且在共享文件夹内
if os.path.isdir(folder_path) and os.path.abspath(folder_path).startswith(os.path.abspath(SHARED_FOLDER)):
try:
# 创建内存中的 ZIP 文件
memory_file = io.BytesIO()
with zipfile.ZipFile(memory_file, 'w', zipfile.ZIP_DEFLATED) as zf:
# 递归添加文件夹中的所有文件
for root, _, files in os.walk(folder_path):
for file in files:
file_path = os.path.join(root, file)
# 计算 ZIP 中的相对路径
rel_path = os.path.relpath(file_path, folder_path)
arcname = os.path.join(foldername, rel_path)
zf.write(file_path, arcname)
memory_file.seek(0)
return Response(
memory_file,
mimetype='application/zip',
headers={'Content-Disposition': f'attachment; filename={foldername}.zip'}
)
except Exception as e:
abort(500, f"错误: 无法创建 ZIP 文件 - {str(e)}")
else:
abort(404, "文件夹不存在或无权访问")
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000, debug=True)
使用说明
安装依赖
确保 Python 3.6+ 已安装,并安装 Flask:
pip install flask
准备文件夹
创建 shared_files
文件夹,或修改 SHARED_FOLDER
为其他路径。在文件夹中放入文件和子文件夹,例如:
shared_files/
├── doc.pdf
├── archive.zip
├── data.tar
├── subfolder/
│ ├── file1.txt
│ ├── file2.png
运行脚本
保存脚本为 file_server_with_zip_tar.py
,并运行:
python file_server_with_zip_tar.py
访问服务
浏览器访问 http://localhost:5000
,页面将显示文件夹内容。点击文件直接下载,点击文件夹将下载为 ZIP 文件。
对外开放
如需公网访问,确保防火墙开放 5000 端口,或修改 port
。建议配置 Nginx 反向代理或 HTTPS 以增强安全性。
示例输出
shared_files
内容:
shared_files/
├── doc.pdf
├── archive.zip
├── data.tar
├── subfolder/
│ ├── file1.txt
│ ├── file2.png
通过上述步骤,用户可以轻松浏览和下载指定文件夹中的文件和子文件夹。