Python Flask发送空文件StringIO

49
我想处理一个 Pandas 数据框并将其作为 CSV 下载,而无需使用临时文件。我见过的最好方法是使用 StringIO。使用以下代码,可以下载一个具有正确名称的文件,但是该文件完全为空,并且没有显示任何错误。为什么文件不包含数据?
@app.route('/test_download', methods = ['POST'])
def test_download():
    buffer = StringIO()
    buffer.write('Just some letters.')
    buffer.seek(0)
    return send_file(
        buffer,
        as_attachment=True,
        download_name='a_file.txt',
        mimetype='text/csv'
    )
4个回答

64

问题在于Python 3中,您需要使用StringIOcsv.write,而send_file需要BytesIO,因此您需要同时使用两者。

@app.route('/test_download')
def test_download():
    row = ['hello', 'world']
    proxy = io.StringIO()
    
    writer = csv.writer(proxy)
    writer.writerow(row)
    
    # Creating the byteIO object from the StringIO Object
    mem = io.BytesIO()
    mem.write(proxy.getvalue().encode())
    # seeking was necessary. Python 3.5.2, Flask 0.12.2
    mem.seek(0)
    proxy.close()

    return send_file(
        mem,
        as_attachment=True,
        download_name='test.csv',
        mimetype='text/csv'
    )

在 Flask 2.0 之前,download_name 被称为 attachment_filename


如果我有一个值不想编码的列,该怎么办? - Tes3awy
我对proxy.close()是否真的必要表示怀疑。无论如何,StringIO对象在视图函数执行结束时都会消失,不是吗? - undefined

29

使用 BytesIO 来写入字节。

from io import BytesIO
from flask import Flask, send_file

app = Flask(__name__)

@app.route('/test_download', methods=['POST'])
def test_download():
    # Use BytesIO instead of StringIO here.
    buffer = BytesIO()
    buffer.write(b'Just some letters.')
    # Or you can encode it to bytes.
    # buffer.write('Just some letters.'.encode('utf-8'))
    buffer.seek(0)
    return send_file(
        buffer,
        as_attachment=True,
        download_name='a_file.txt',
        mimetype='text/csv'
    )

在 Flask 2.0 之前,download_name 被称为 attachment_filename


2

make_response

  • 为了让Flask将一个csv文件下载给用户,我们将csv字符串传递给make_response函数,该函数返回一个Response对象。
  • 然后,我们添加一个Header,告诉浏览器接受该文件作为下载。
  • 此外,Mimetype也必须设置为text/csv,以便让Web浏览器将其保存为除html文档之外的其他格式。
from flask import Flask, make_response  
app = Flask(__name__)

@app.route('/test_download', methods=['POST'])
def test_download():
    with StringIO() as buffer:
        # forming a StringIO object  
        buffer = StringIO()
        buffer.write('Just some letters.')
        # forming a Response object with Headers to return from flask 
        response = make_response(buffer.getvalue())
        response.headers['Content-Disposition'] = 'attachment; filename=namaste.csv'
        response.mimetype = 'text/csv'
        # return the Response object
        return response

注:最好使用Python内置的csv库来处理csv文件。

参考资料

Namaste


0

如果有人在使用Python 2.7和Flask时导入StringIO模块时遇到错误,本文可以帮助您解决问题。

如果您正在导入StringIO模块,您只需更改导入语法,使用from io import StringIO而不是from StringIO import StringIO

如果您正在使用图像或其他资源,您也可以使用from io import BytesIO

谢谢


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