您现在的位置是:首页 > 技术教程 正文

Flask框架上传和下载文件

admin 阅读: 2024-03-26
后台-插件-广告管理-内容页头部广告(手机)

1、Flask上传文件

上传文件步骤

1. 在模版html中,表单需要指定 enctype='multipart/form-data' 才能上传文件。

2. 在后台如果想要获取上传的文件,那么应该使用 request.files.get('文件名') 来获取。

3. 保存文件之前,先要使用 werkzeug.utils.secure_filename 来对上传上来的文件名进行一个过滤。能保证不会有安全问题。

4. 获取到上传上来的文件后,使用 文件对象.save(路径) 方法来保存文件。路径=完整路径=路径名+文件名

示例代码:

main.py

  1. from flask import Flask, render_template, request
  2. from werkzeug.utils import secure_filename
  3. import os
  4. app = Flask(__name__)
  5. UPLOAD_PATH = os.path.join(os.path.dirname(__file__), 'images')
  6. @app.route('/')
  7. def index():
  8. return 'Hello! '
  9. @app.route('/upload/', methods=['GET', 'POST'])
  10. def upload():
  11. if request.method == 'GET':
  12. return render_template('upload.html')
  13. else:
  14. img_file = request.files.get('pic')
  15. file_name = img_file.filename
  16. # 文件名的安全转换
  17. filename = secure_filename(file_name)
  18. # 保存文件
  19. img_file.save(os.path.join(UPLOAD_PATH, filename))
  20. return '上传文件成功!'
  21. if __name__ == '__main__':
  22. app.run(debug=True)

upload.html

  1. "en">
  2. "UTF-8">
  3. "X-UA-Compatible" content="IE=edge">
  4. "viewport" content="width=device-width, initial-scale=1.0">
  5. Document
  6. "/upload/" method="post" enctype="multipart/form-data">
  7. 上传文件:<input type="file" name="pic">
  8. <input type="submit" value="提交">

运行结果:

系统路径中生成的文件:

2、Flask下载文件

2.1 send_from_directory方法

从服务器上读取文件,应该定义一个url与视图函数,来获取指定的文件。

在这个视图函数中,使用 send_from_directory(文件的目录,文件名) 来获取。

send_from_direction函数底层实现:

  1. def send_from_directory(directory, filename, **options):
  2. """Send a file from a given directory with :func:`send_file`. This
  3. is a secure way to quickly expose static files from an upload folder
  4. or something similar.
  5. Example usage::
  6. @app.route('/uploads/')
  7. def download_file(filename):
  8. return send_from_directory(app.config['UPLOAD_FOLDER'],
  9. filename, as_attachment=True)
  10. .. admonition:: Sending files and Performance
  11. It is strongly recommended to activate either ``X-Sendfile`` support in
  12. your webserver or (if no authentication happens) to tell the webserver
  13. to serve files for the given path on its own without calling into the
  14. web application for improved performance.
  15. .. versionadded:: 0.5
  16. :param directory: the directory where all the files are stored.
  17. :param filename: the filename relative to that directory to
  18. download.
  19. :param options: optional keyword arguments that are directly
  20. forwarded to :func:`send_file`.
  21. """
  22. filename = fspath(filename)
  23. directory = fspath(directory)
  24. filename = safe_join(directory, filename)
  25. if not os.path.isabs(filename):
  26. filename = os.path.join(current_app.root_path, filename)
  27. try:
  28. if not os.path.isfile(filename):
  29. raise NotFound()
  30. except (TypeError, ValueError):
  31. raise BadRequest()
  32. options.setdefault("conditional", True)
  33. return send_file(filename, **options)

示例代码:

目前服务器中存在的文件:

  1. from flask import Flask, send_from_directory
  2. import os
  3. app = Flask(__name__)
  4. UPLOAD_PATH = os.path.join(os.path.dirname(__file__), 'images')
  5. @app.route('/download//')
  6. def download_file(filename):
  7. return send_from_directory(UPLOAD_PATH, filename)
  8. # return send_from_directory(UPLOAD_PATH, filename, as_attachment=True)
  9. if __name__ == '__main__':
  10. app.run(debug=True)

运行结果:

当参数as_attachment=True时:

2.2 send_file方法

send_file()函数:

  1. def send_file(
  2. path_or_file: t.Union[os.PathLike, str, t.BinaryIO],
  3. mimetype: t.Optional[str] = None,
  4. as_attachment: bool = False,
  5. download_name: t.Optional[str] = None,
  6. attachment_filename: t.Optional[str] = None,
  7. conditional: bool = True,
  8. etag: t.Union[bool, str] = True,
  9. add_etags: t.Optional[bool] = None,
  10. last_modified: t.Optional[t.Union[datetime, int, float]] = None,
  11. max_age: t.Optional[
  12. t.Union[int, t.Callable[[t.Optional[str]], t.Optional[int]]]
  13. ] = None,
  14. cache_timeout: t.Optional[int] = None,
  15. ):

参数解析:

  • path_or_file:要发送的文件的路径,如果给出了相对路径,则相对于当前工作目录。或者,以二进制模式打开的类文件对象。确保将文件指针查找到数据的开头。
  • mimetype:为文件发送的MIME类型。如果没有提供,它将尝试从文件名检测它。
  • as_attachment:指示浏览器应该提供给保存文件而不是显示它。
  • download_name:浏览器保存文件时使用的默认名称。默认为传递的文件名。
  • conditional:基于请求头启用条件响应和范围响应。需要传递一个文件路径和``environ``。
  • etag:计算文件的etag,这需要传递一个文件路径。也可以是字符串来代替。
  • last_modified:发送文件的最后修改时间,单位为秒。如果没有提供,它将尝试从文件路径检测它。
  • max_age:客户端应该缓存文件多长时间,以秒为单位。如果设置,' ' Cache-Control ' '将为' ' public ' ',否则将为' ' no-cache ' '以选择条件缓存。

注意:

示例代码:

  1. import os
  2. from flask import Flask, send_file, request, render_template, redirect
  3. from werkzeug.utils import secure_filename
  4. app = Flask(__name__)
  5. UPLOAD_FOLDER = 'media' # 注意:要提前在根目录下新建media文件,否则会报错
  6. app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
  7. # 判断上传的文件是否是允许的后缀
  8. def allowed_file(filename):
  9. return "." in filename and filename.rsplit('.', 1)[1].lower() in set(['txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif'])
  10. @app.route('/')
  11. def index():
  12. return "hello world!"
  13. @app.route('/generate_file')
  14. def generate_file():
  15. with open('./new_file.txt', 'w', encoding='utf-8') as f:
  16. f.write('我是new_file.txt文件!')
  17. return "<./new_file.txt>文件已经生成!"
  18. @app.route('/download')
  19. def download():
  20. return send_file('./new_file.txt', as_attachment=True)
  21. @app.route('/upload', methods=['GET', 'POST'])
  22. def upload():
  23. if request.method == 'GET':
  24. return render_template('upload.html')
  25. else:
  26. if "file" not in request.files:
  27. return redirect(request.url)
  28. file = request.files.get('file') # 获取文件
  29. # 上传空文件(无文件)
  30. if file.filename == '':
  31. return redirect(request.url)
  32. if file and allowed_file(file.filename):
  33. if not os.path.exists(f'./templates/{UPLOAD_FOLDER}'):
  34. os.mkdir(f'./templates/{UPLOAD_FOLDER}')
  35. filename = secure_filename(file.filename) # 用这个函数确定文件名称是否是安全 (注意:中文不能识别)
  36. file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename)) # 保存文件
  37. return "上传文件成功!"
  38. if __name__ == '__main__':
  39. app.run()

下载和上传路径中可以添加用户身份验证:

  1. import os
  2. from flask import Flask, send_file, request, render_template, redirect
  3. from werkzeug.utils import secure_filename
  4. app = Flask(__name__)
  5. UPLOAD_FOLDER = 'media' # 注意:要提前在根目录下新建media文件,否则会报错
  6. app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
  7. allow_users = ['dgw', 'super_user']
  8. # 判断上传的文件是否是允许的后缀
  9. def allowed_file(filename):
  10. return "." in filename and filename.rsplit('.', 1)[1].lower() in set(['txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif'])
  11. @app.route('/')
  12. def index():
  13. return "hello world!"
  14. @app.route('/generate_file')
  15. def generate_file():
  16. with open('./new_file.txt', 'w', encoding='utf-8') as f:
  17. f.write('我是new_file.txt文件!')
  18. return "<./new_file.txt>文件已经生成!"
  19. @app.route('/download')
  20. def download():
  21. user_name = request.args.get('user_name')
  22. if not user_name:
  23. return "你没有权限下载文件!"
  24. if user_name and user_name not in allow_users:
  25. return "你没有权限下载文件!"
  26. return send_file('./new_file.txt', as_attachment=True)
  27. @app.route('/upload/', methods=['GET', 'POST'])
  28. def upload(user_name):
  29. if request.method == 'GET':
  30. if user_name not in allow_users:
  31. return "您没有权限访问此页面!"
  32. return render_template('upload.html')
  33. else:
  34. if user_name not in allow_users:
  35. return "您没有权限访问此页面!"
  36. if "file" not in request.files:
  37. return redirect(request.url)
  38. file = request.files.get('file') # 获取文件
  39. # 上传空文件(无文件)
  40. if file.filename == '':
  41. return redirect(request.url)
  42. if file and allowed_file(file.filename):
  43. if not os.path.exists(f'./templates/{UPLOAD_FOLDER}'):
  44. os.mkdir(f'./templates/{UPLOAD_FOLDER}')
  45. filename = secure_filename(file.filename) # 用这个函数确定文件名称是否是安全 (注意:中文不能识别)
  46. file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename)) # 保存文件
  47. return "上传文件成功!"
  48. if __name__ == '__main__':
  49. app.run()

upload.html

  1. html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Uploadtitle>
  6. head>
  7. <body>
  8. <form action="" method="post" enctype="multipart/form-data">
  9. <input type="file" name="file">
  10. <input type="submit" value="上传">
  11. form>
  12. body>
  13. html>

3、Flask-wtf验证上传的文件

关键点:

  1. 定义验证表单类的时候,对文件类型的字段,需要采用 FileField 这个类型,即wtforms.FileField
  2. 验证器需要从 flask_wtf.file 中导入。 flask_wtf.file.FileRequired 和 flask_wtf.file.FileAllowed
  3. flask_wtf.file.FileRequired 是用来验证文件上传不能为空。
  4. flask_wtf.file.FileAllowed 用来验证上传的文件的后缀名, 如常见图片后缀 .jpg 和.png以及.gif等。
  5. 在视图函数中,需要使用 from werkzeug.datastructures import CombinedMultiDict 来把request.form 与 request.files 来进行合并。
  6. 最后使用 表单验证对象.validate()进行验证。

示例代码:

main.py

  1. from flask import Flask, render_template, request
  2. from werkzeug.datastructures import CombinedMultiDict
  3. from werkzeug.utils import secure_filename
  4. import os
  5. from formcheck import UpLoadForm
  6. app = Flask(__name__)
  7. UPLOAD_PATH = os.path.join(os.path.dirname(__file__), 'images')
  8. @app.route('/upload/', methods=['GET', 'POST'])
  9. def upload():
  10. if request.method == 'GET':
  11. return render_template('upload.html')
  12. else:
  13. form = UpLoadForm(CombinedMultiDict([request.form, request.files]))
  14. if form.validate():
  15. img_file = form.pic.data
  16. file_name = secure_filename(img_file.filename)
  17. img_file.save(os.path.join(UPLOAD_PATH, file_name))
  18. return '上传文件成功!'
  19. else:
  20. return f'{form.errors}'
  21. if __name__ == '__main__':
  22. app.run(debug=True)

formcheck.py

  1. from wtforms import Form, FileField
  2. from flask_wtf.file import FileAllowed, FileRequired
  3. class UpLoadForm(Form):
  4. pic = FileField(validators=[FileRequired(), FileAllowed(['jpg', 'png', 'gif'])])

upload.py

  1. html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta http-equiv="X-UA-Compatible" content="IE=edge">
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  7. <title>Documenttitle>
  8. head>
  9. <body>
  10. <form action="/upload/" method="post" enctype="multipart/form-data">
  11. 上传文件:<input type="file" name="pic"><br>
  12. <input type="submit" value="提交">
  13. form>
  14. body>
  15. html>

运行结果:

参考博文:

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

标签:
声明

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

在线投稿:投稿 站长QQ:1888636

后台-插件-广告管理-内容页尾部广告(手机)
关注我们

扫一扫关注我们,了解最新精彩内容

搜索
排行榜