在Flask中读取文件数据而无需保存它

162

我正在编写我的第一个Flask应用程序。我正在处理文件上传,基本上我想做的是在不保存数据的情况下读取上传文件的数据/内容,然后将其打印到结果页面上。是的,我假设用户总是上传文本文件。

这是我正在使用的简单上传函数:

@app.route('/upload/', methods=['GET', 'POST'])
def upload():
    if request.method == 'POST':
        file = request.files['file']
        if file:
            filename = secure_filename(file.filename)
            file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
            a = 'file uploaded'

    return render_template('upload.html', data = a)

现在,我正在保存文件,但我需要的是变量'a'包含文件的内容/数据..有什么想法吗?

8个回答

183

FileStorage 包含 stream 字段。该对象必须扩展 IO 或文件对象,因此它必须包含 read 和其他类似的方法。 FileStorage 还扩展了 stream 字段对象属性,因此您可以只使用 file.read() 而不是 file.stream.read()。此外,您可以使用 save 参数和 dst 参数作为 StringIO 或其他 IO 或文件对象将 FileStorage.stream 拷贝到另一个 IO 或文件对象。

请参阅文档:http://flask.pocoo.org/docs/api/#flask.Request.fileshttp://werkzeug.pocoo.org/docs/datastructures/#werkzeug.datastructures.FileStorage


3
快速示例:file = request.files.get('file') filetype = magic.from_buffer(file.read(1024)) 翻译:获取文件:file = request.files.get('file'),通过读取文件前1024个字节获取文件类型:filetype = magic.from_buffer(file.read(1024)) - endolith
8
嗨@user2480542。我遇到了同样的问题。你可以描述一下你是如何读取客户上传文件的内容吗?我调用了file.read()但是没有得到任何东西。谢谢! - tmthyjames
1
@tmthyjames f = request.files['file'] 将上传的文件(在请求中)放到变量“f”中。然后,使用上面的代码f.read()。当执行print f.read()时,终端会输出正确的文件内容。希望这可以帮到你。 - Marc
6
如果你正在上传一个文件,并且拥有一个二进制流,你可以通过将它放入TextIOWrapper中来轻松地将其转换为文本流:mystring = TextIOWrapper(binary_stream)。注意不要改变原意,使翻译更加通俗易懂。 - Dutch Masters
17
对我来说,f.read() 也没有产生任何结果。调用 f.seek(0) 首先可以解决这个问题。 - w177us
显示剩余6条评论

20
如果您想使用标准的Flask内容 - 如果上传的文件大小大于500kb,则无法避免保存临时文件。如果小于500kb,则会使用“BytesIO”,将文件内容存储在内存中;如果大于500kb,则将内容存储在TemporaryFile()中(正如werkzeug文档中所述)。在这两种情况下,您的脚本都将阻塞,直到接收到完整的上传文件。
最简单的解决方法是:
1)创建您自己的文件IO类,在其中处理所有传入数据
2)在您的脚本中,使用您自己的Request类进行覆盖:
class MyRequest( Request ):
  def _get_file_stream( self, total_content_length, content_type, filename=None, content_length=None ):
    return MyAwesomeIO( filename, 'w' )

3) 使用你自己的request_class替换Flask的request_class:

app.request_class = MyRequest

4)去喝一些啤酒吧 :)


在那段代码中,MyAwesomeIO是什么? - Superdooperhero
一个类似文件的对象,实现了所有标准文件方法(打开、关闭、读取等)。在我的情况下,它是一个自定义类,实现了所有标准方法,但使用远程数据存储来存储数据。这样就不需要在将其发送到远程存储解决方案之前在本地存储临时文件了。 - dniq

7
我分享我的解决方案(假设一切都已经配置好以连接到 Flask 中的 Google Bucket)。
from google.cloud import storage

@app.route('/upload/', methods=['POST'])
def upload():
    if request.method == 'POST':
        # FileStorage object wrapper
        file = request.files["file"]                    
        if file:
            os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = app.config['GOOGLE_APPLICATION_CREDENTIALS']
            bucket_name = "bucket_name" 
            storage_client = storage.Client()
            bucket = storage_client.bucket(bucket_name)
            # Upload file to Google Bucket
            blob = bucket.blob(file.filename) 
            blob.upload_from_string(file.read())

我的帖子

如何在 Flask 中直接访问 Google Bucket


3
我分享我的解决方案,使用pandas。

@app.route('/upload/', methods=['POST'])
def upload():
    if request.method == 'POST':
        # FileStorage object wrapper
        file = request.files["file"]                    
        if file:
            df = pd.read_excel(files_excel["file"])

request.files["file"]是本地文件系统上的临时文件。它并不能解决原始问题。 - dniq

3
我想做同样的事情,打开一个文本文件(实际上是 Pandas 的 CSV 文件)。不想复制它,只想打开它。表单-WTF 有一个很好的文件浏览器,但它会打开文件并创建一个临时文件,然后将其呈现为内存流。在底层进行一些工作后,
form = UploadForm() 
 if form.validate_on_submit(): 
      filename = secure_filename(form.fileContents.data.filename)  
      filestream =  form.fileContents.data 
      filestream.seek(0)
      ef = pd.read_csv( filestream  )
      sr = pd.DataFrame(ef)  
      return render_template('dataframe.html',tables=[sr.to_html(justify='center, classes='table table-bordered table-hover')],titles = [filename], form=form) 

2

在@tbicr的优秀回答基础上,最简单的形式可以概括为:

for line in request.files.get('file'):
   print("Next line: " + line)

-2

在函数中

def handleUpload():
    if 'photo' in request.files:
        photo = request.files['photo']
        if photo.filename != '':      
            image = request.files['photo']  
            image_string = base64.b64encode(image.read())
            image_string = image_string.decode('utf-8')
            #use this to remove b'...' to get raw string
            return render_template('handleUpload.html',filestring = image_string)
    return render_template('upload.html')

在 HTML 文件中

<html>
<head>
    <title>Simple file upload using Python Flask</title>
</head>
<body>
    {% if filestring %}
      <h1>Raw image:</h1>
      <h1>{{filestring}}</h1>
      <img src="data:image/png;base64, {{filestring}}" alt="alternate" />.
    {% else %}
      <h1></h1>
    {% endif %}
</body>


-3

如果我们想要将内存中的文件转储到磁盘上,可以使用这段代码

  if isinstanceof(obj,SpooledTemporaryFile):
    obj.rollover()


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接