【问题标题】:Not able to parse a .csv file uploaded using Flask无法解析使用 Flask 上传的 .csv 文件
【发布时间】:2018-07-04 05:44:36
【问题描述】:

我正在尝试上传一个 CSV 文件,对其进行处理以产生结果,然后写回(下载)一个包含结果的新 CSV 文件。 我对 Flask 很陌生,我无法获得一个“正确的”csv.reader 对象来迭代和处理。 这是到目前为止的代码,

__author__ = 'shivendra'
from flask import Flask, make_response, request
import csv

app = Flask(__name__)

def transform(text_file_contents):
    return text_file_contents.replace("=", ",")


@app.route('/')
def form():
    return """
        <html>
            <body>
                <h1>Transform a file demo</h1>

                <form action="/transform" method="post" enctype="multipart/form-data">
                    <input type="file" name="data_file" />
                    <input type="submit" />
                </form>
            </body>
        </html>
    """

@app.route('/transform', methods=["POST"])
def transform_view():
    file = request.files['data_file']
    if not file:
        return "No file"

    file_contents = file.stream.read().decode("utf-8")
    csv_input = csv.reader(file_contents)
    print(file_contents)
    print(type(file_contents))
    print(csv_input)
    for row in csv_input:
        print(row)

    result = transform(file_contents)

    response = make_response(result)
    response.headers["Content-Disposition"] = "attachment; filename=result.csv"
    return response

if __name__ == "__main__":
    app.run(host='0.0.0.0', port=5001, debug=True)

终端输出是

127.0.0.1 - - [12/Oct/2015 02:51:53] "GET / HTTP/1.1" 200 -
127.0.0.1 - - [12/Oct/2015 02:51:59] "POST /transform HTTP/1.1" 200 -
4,5,6
<class 'str'>
<_csv.reader object at 0x105149438>
['1']
['', '']
['2']
['', '']
['3']
[]
['4']
['', '']
['5']
['', '']
['6']

而我读到的文件是

当我迭代 csv.reader 对象时没有得到代表 2 行的 2 个列表,我做错了什么?

【问题讨论】:

  • 您能否以文本格式而不是电子表格程序显示您的 csv 文件的外观。另外,您使用什么电子表格程序来生成 csv(如果有)。还有一件事,为什么必须用, 替换=?大多数 csv 方言不使用等号。
  • @iLoveTux 用, 替换= 是完全没有必要的。变换现在是一个虚拟函数。但我一直无法到达那里,因为我被困在 csv 阅读部分。
  • 添加了csv的文本文件图片。
  • 这个站点上的 cmets 的格式很奇怪。那是3到4之间的换行符吗?通过遍历您的 csv 的结果,似乎每个数字后面都有一个回车符 \r 或换行符 \n,但如果不是这样,我需要一个 csv 文件的实际副本来播放为了弄清楚
  • 是的,这很奇怪。我将文件上传到dropbox.com/s/xmgn8n3o9leor12/blog1.csv?dl=0

标签: python csv flask


【解决方案1】:

好的,所以您的脚本存在一个主要问题,csv.reader 如上所述,here 需要一个文件对象或至少一个支持迭代器协议的对象。您正在传递一个str,它确实实现了迭代器协议,但它不是遍历行,而是遍历字符。这就是为什么你有你做的输出。

首先,它给出了一个单一的字符1csv.reader 将其视为一个包含一个字段的行。之后,str 给出了另一个单个字符 ,csv.reader 将其视为具有两个空字段的行(因为逗号是字段分隔符)。它在整个str 中一直如此,直到它筋疲力尽。

解决方案(或至少一个解决方案)是将str 转换为类似文件的对象。我尝试使用flask.request.files["name"] 提供的流,但这并没有遍历这些行。接下来,我尝试使用cStringIO.StringIO,这似乎有类似的问题。我最终遇到了this 问题,该问题建议使用通用换行模式下的io.StringIO 对象,该对象有效。我最终得到了以下工作代码(也许它可能会更好):

__author__ = 'shivendra'
from flask import Flask, make_response, request
import io
import csv

app = Flask(__name__)

def transform(text_file_contents):
    return text_file_contents.replace("=", ",")


@app.route('/')
def form():
    return """
        <html>
            <body>
                <h1>Transform a file demo</h1>

                <form action="/transform" method="post" enctype="multipart/form-data">
                    <input type="file" name="data_file" />
                    <input type="submit" />
                </form>
            </body>
        </html>
    """

@app.route('/transform', methods=["POST"])
def transform_view():
    f = request.files['data_file']
    if not f:
        return "No file"

    stream = io.StringIO(f.stream.read().decode("UTF8"), newline=None)
    csv_input = csv.reader(stream)
    #print("file contents: ", file_contents)
    #print(type(file_contents))
    print(csv_input)
    for row in csv_input:
        print(row)

    stream.seek(0)
    result = transform(stream.read())

    response = make_response(result)
    response.headers["Content-Disposition"] = "attachment; filename=result.csv"
    return response

if __name__ == "__main__":
    app.run(host='0.0.0.0', port=5001, debug=True)

【讨论】:

  • 谢谢,我无法告诉你我多么感激你的努力。有效。你不仅解决了我的问题,还帮助我正确理解了每一行代码。你太棒了。
  • 好的,感谢您的详细回复。在网上找到合适的回应并不容易。你做到了;)
【解决方案2】:

重要提示:此答案仅适用于SpooledTemporaryFile 可用的平台。

iLuveTux answer 的基础上,您可以通过替换以下基于字符串的流创建来节省多余的read() 调用:

stream = io.StringIO(f.stream.read().decode("UTF8"), newline=None)

与:

stream = io.TextIOWrapper(f.stream._file, "UTF8", newline=None)

例子:

stream = io.TextIOWrapper(f.stream._file, "UTF8", newline=None)
csv_input = csv.reader(stream)
print(csv_input)
for row in csv_input:
    print(row)

更多信息:

Werkzeug 表单数据解析器的默认流是SpooledTemporaryFile(截至1.0.1),您可以使用其_file 成员从中获取底层缓冲区。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-02
    • 2016-07-04
    • 1970-01-01
    • 1970-01-01
    • 2019-04-17
    相关资源
    最近更新 更多