1. 在模版html中,表单需要指定 enctype='multipart/form-data' 才能上传文件。
2. 在后台如果想要获取上传的文件,那么应该使用 request.files.get('文件名') 来获取。
3. 保存文件之前,先要使用 werkzeug.utils.secure_filename 来对上传上来的文件名进行一个过滤。能保证不会有安全问题。
4. 获取到上传上来的文件后,使用 文件对象.save(路径) 方法来保存文件。路径=完整路径=路径名+文件名
示例代码:
main.py
from flask import Flask, render_template, request
from werkzeug.utils import secure_filename
import os
app = Flask(__name__)
UPLOAD_PATH = os.path.join(os.path.dirname(__file__), 'images')
@app.route('/')
def index():
return 'Hello! '
@app.route('/upload/', methods=['GET', 'POST'])
def upload():
if request.method == 'GET':
return render_template('upload.html')
else:
img_file = request.files.get('pic')
file_name = img_file.filename
# 文件名的安全转换
filename = secure_filename(file_name)
# 保存文件
img_file.save(os.path.join(UPLOAD_PATH, filename))
return '上传文件成功!'
if __name__ == '__main__':
app.run(debug=True)
upload.html
Document
运行结果:



系统路径中生成的文件:

从服务器上读取文件,应该定义一个url与视图函数,来获取指定的文件。
在这个视图函数中,使用 send_from_directory(文件的目录,文件名) 来获取。
send_from_direction函数底层实现:
def send_from_directory(directory, filename, **options):
"""Send a file from a given directory with :func:`send_file`. This
is a secure way to quickly expose static files from an upload folder
or something similar.
Example usage::
@app.route('/uploads/')
def download_file(filename):
return send_from_directory(app.config['UPLOAD_FOLDER'],
filename, as_attachment=True)
.. admonition:: Sending files and Performance
It is strongly recommended to activate either ``X-Sendfile`` support in
your webserver or (if no authentication happens) to tell the webserver
to serve files for the given path on its own without calling into the
web application for improved performance.
.. versionadded:: 0.5
:param directory: the directory where all the files are stored.
:param filename: the filename relative to that directory to
download.
:param options: optional keyword arguments that are directly
forwarded to :func:`send_file`.
"""
filename = fspath(filename)
directory = fspath(directory)
filename = safe_join(directory, filename)
if not os.path.isabs(filename):
filename = os.path.join(current_app.root_path, filename)
try:
if not os.path.isfile(filename):
raise NotFound()
except (TypeError, ValueError):
raise BadRequest()
options.setdefault("conditional", True)
return send_file(filename, **options)
示例代码:
目前服务器中存在的文件:

from flask import Flask, send_from_directory
import os
app = Flask(__name__)
UPLOAD_PATH = os.path.join(os.path.dirname(__file__), 'images')
@app.route('/download//')
def download_file(filename):
return send_from_directory(UPLOAD_PATH, filename)
# return send_from_directory(UPLOAD_PATH, filename, as_attachment=True)
if __name__ == '__main__':
app.run(debug=True)
运行结果:

当参数as_attachment=True时:

send_file()函数:
def send_file(
path_or_file: t.Union[os.PathLike, str, t.BinaryIO],
mimetype: t.Optional[str] = None,
as_attachment: bool = False,
download_name: t.Optional[str] = None,
attachment_filename: t.Optional[str] = None,
conditional: bool = True,
etag: t.Union[bool, str] = True,
add_etags: t.Optional[bool] = None,
last_modified: t.Optional[t.Union[datetime, int, float]] = None,
max_age: t.Optional[
t.Union[int, t.Callable[[t.Optional[str]], t.Optional[int]]]
] = None,
cache_timeout: t.Optional[int] = None,
):
参数解析:
注意:

示例代码:
import os
from flask import Flask, send_file, request, render_template, redirect
from werkzeug.utils import secure_filename
app = Flask(__name__)
UPLOAD_FOLDER = 'media' # 注意:要提前在根目录下新建media文件,否则会报错
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
# 判断上传的文件是否是允许的后缀
def allowed_file(filename):
return "." in filename and filename.rsplit('.', 1)[1].lower() in set(['txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif'])
@app.route('/')
def index():
return "hello world!"
@app.route('/generate_file')
def generate_file():
with open('./new_file.txt', 'w', encoding='utf-8') as f:
f.write('我是new_file.txt文件!')
return "<./new_file.txt>文件已经生成!"
@app.route('/download')
def download():
return send_file('./new_file.txt', as_attachment=True)
@app.route('/upload', methods=['GET', 'POST'])
def upload():
if request.method == 'GET':
return render_template('upload.html')
else:
if "file" not in request.files:
return redirect(request.url)
file = request.files.get('file') # 获取文件
# 上传空文件(无文件)
if file.filename == '':
return redirect(request.url)
if file and allowed_file(file.filename):
if not os.path.exists(f'./templates/{UPLOAD_FOLDER}'):
os.mkdir(f'./templates/{UPLOAD_FOLDER}')
filename = secure_filename(file.filename) # 用这个函数确定文件名称是否是安全 (注意:中文不能识别)
file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename)) # 保存文件
return "上传文件成功!"
if __name__ == '__main__':
app.run()
下载和上传路径中可以添加用户身份验证:
import os
from flask import Flask, send_file, request, render_template, redirect
from werkzeug.utils import secure_filename
app = Flask(__name__)
UPLOAD_FOLDER = 'media' # 注意:要提前在根目录下新建media文件,否则会报错
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
allow_users = ['dgw', 'super_user']
# 判断上传的文件是否是允许的后缀
def allowed_file(filename):
return "." in filename and filename.rsplit('.', 1)[1].lower() in set(['txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif'])
@app.route('/')
def index():
return "hello world!"
@app.route('/generate_file')
def generate_file():
with open('./new_file.txt', 'w', encoding='utf-8') as f:
f.write('我是new_file.txt文件!')
return "<./new_file.txt>文件已经生成!"
@app.route('/download')
def download():
user_name = request.args.get('user_name')
if not user_name:
return "你没有权限下载文件!"
if user_name and user_name not in allow_users:
return "你没有权限下载文件!"
return send_file('./new_file.txt', as_attachment=True)
@app.route('/upload/', methods=['GET', 'POST'])
def upload(user_name):
if request.method == 'GET':
if user_name not in allow_users:
return "您没有权限访问此页面!"
return render_template('upload.html')
else:
if user_name not in allow_users:
return "您没有权限访问此页面!"
if "file" not in request.files:
return redirect(request.url)
file = request.files.get('file') # 获取文件
# 上传空文件(无文件)
if file.filename == '':
return redirect(request.url)
if file and allowed_file(file.filename):
if not os.path.exists(f'./templates/{UPLOAD_FOLDER}'):
os.mkdir(f'./templates/{UPLOAD_FOLDER}')
filename = secure_filename(file.filename) # 用这个函数确定文件名称是否是安全 (注意:中文不能识别)
file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename)) # 保存文件
return "上传文件成功!"
if __name__ == '__main__':
app.run()
upload.html
Upload
关键点:
示例代码:
main.py
from flask import Flask, render_template, request
from werkzeug.datastructures import CombinedMultiDict
from werkzeug.utils import secure_filename
import os
from formcheck import UpLoadForm
app = Flask(__name__)
UPLOAD_PATH = os.path.join(os.path.dirname(__file__), 'images')
@app.route('/upload/', methods=['GET', 'POST'])
def upload():
if request.method == 'GET':
return render_template('upload.html')
else:
form = UpLoadForm(CombinedMultiDict([request.form, request.files]))
if form.validate():
img_file = form.pic.data
file_name = secure_filename(img_file.filename)
img_file.save(os.path.join(UPLOAD_PATH, file_name))
return '上传文件成功!'
else:
return f'{form.errors}'
if __name__ == '__main__':
app.run(debug=True)
formcheck.py
from wtforms import Form, FileField
from flask_wtf.file import FileAllowed, FileRequired
class UpLoadForm(Form):
pic = FileField(validators=[FileRequired(), FileAllowed(['jpg', 'png', 'gif'])])
upload.py
Document
运行结果:






参考博文:
Python Flask 文件下载_flask下载_liyinchi1988的博客-CSDN博客