在Google App Engine上使用Python上传并解析带有“通用换行符”的CSV文件
我正在从一个表单上传一个csv或tsv文件到GAE(谷歌应用引擎),然后我尝试用Python的csv模块来解析这个文件。
正如这里所描述的,GAE中上传的文件其实是字符串。
所以我把我上传的字符串当作一个文件对象来处理:
file = self.request.get('catalog')
catalog = csv.reader(StringIO.StringIO(file),dialect=csv.excel_tab)
但是我发现文件中的换行符不一定是'\n'(这都是因为Excel的原因..),这就导致了一个错误:
错误:在未加引号的字段中发现换行符 - 你是否需要以通用换行模式打开文件?
有没有人知道怎么用StringIO.StringIO来把字符串当作以通用换行模式打开的文件来处理?
2 个回答
4
这里描述的解决方案 应该是可行的。通过定义一个迭代器类,具体做法是每次加载1MB的数据,使用.splitlines()来分割行,然后逐行把这些行传给CSV读取器,这样就可以处理换行符,而不需要把整个文件都加载到内存中。
class BlobIterator:
"""Because the python csv module doesn't like strange newline chars and
the google blob reader cannot be told to open in universal mode, then
we need to read blocks of the blob and 'fix' the newlines as we go"""
def __init__(self, blob_reader):
self.blob_reader = blob_reader
self.last_line = ""
self.line_num = 0
self.lines = []
self.buffer = None
def __iter__(self):
return self
def next(self):
if not self.buffer or len(self.lines) == self.line_num + 1:
self.buffer = self.blob_reader.read(1048576) # 1MB buffer
self.lines = self.buffer.splitlines()
self.line_num = 0
# Handle special case where our block just happens to end on a new line
if self.buffer[-1:] == "\n" or self.buffer[-1:] == "\r":
self.lines.append("")
if not self.buffer:
raise StopIteration
if self.line_num == 0 and len(self.last_line) > 0:
result = self.last_line + self.lines[self.line_num] + "\n"
else:
result = self.lines[self.line_num] + "\n"
self.last_line = self.lines[self.line_num + 1]
self.line_num += 1
return result
然后可以这样调用:
blob_reader = blobstore.BlobReader(blob_key)
blob_iterator = BlobIterator(blob_reader)
reader = csv.reader(blob_iterator)
5
这样怎么样:
file = self.request.get('catalog')
file = '\n'.join(file.splitlines())
catalog = csv.reader(StringIO.StringIO(file),dialect=csv.excel_tab)
或者正如评论中提到的,csv.reader()
可以直接从列表中读取数据,所以可以这样做:
file = self.request.get('catalog')
catalog = csv.reader(file.splitlines(),dialect=csv.excel_tab)
或者如果将来request.get
支持读取模式的话:
file = self.request.get('catalog', 'rU')
catalog = csv.reader(StringIO.StringIO(file),dialect=csv.excel_tab)