我正在尝试上传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个列表,我做错了什么?
答案 0 :(得分:38)
好的,所以你的脚本有一个主要问题,csv.reader
如前所述here需要一个文件对象或至少一个支持迭代器协议的对象。您正在传递一个实现迭代器协议的str
,但它不是遍历这些行,而是遍历字符。这就是你有输出的原因。
首先,它给出了一个单一字符1
,csv.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)
答案 1 :(得分: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
成员从中获取基础缓冲区。