2011-03-17 73 views
9

我从GAE的表单上传了一个csv/tsv文件,我尝试用python csv模块解析文件。在Google App Engine上用python上传和解析csv文件

Like describe here,上传的GAE文件是字符串。
所以我把我的上传一个类文件对象:

file = self.request.get('catalog') 
catalog = csv.reader(StringIO.StringIO(file),dialect=csv.excel_tab) 

但在我的文件的新线不一定“\ n”(感谢练成..),并产生一个错误:
错误:在未加引号的字段中显示换行符 - 是否需要以通用换行符模式打开文件?

有谁知道如何使用StringIO.StringIO来处理像在universal-newline中打开的文件字符串?

+0

根据Python文档,StringIO的默认模式是普遍的换行符。陌生人可能会在您的数据文件中发生。 – Calvin 2011-03-17 16:57:16

+0

@Calvin _“根据Python文档,StringIO的默认模式是通用换行符”_我没有找到文档说的位置,可以显示它吗? – eyquem 2013-09-27 23:24:23

+0

@eyquem已经有2。5年了,所以文档可能已经改变了,但是http://docs.python.org/3.3/library/io.html?highlight=stringio#io.StringIO说'新行参数的工作方式与TextIOWrapper类似'和TextIOWrapper说'如果换行符是None,则启用通用换行符模式。但是,然后StringIO可能会违背这一点,说'默认不做新行翻译。' – Calvin 2013-09-27 23:59:02

回答

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) 
+0

我实际上使用.splitlines(),但我工作在非常大的文件,它不是很快。 request.get()不支持读取模式。 – greg 2011-03-17 16:27:20

+1

@greg:然后你卡住了。您可以通过执行.replace('\ r \ n','\ n')来模拟它,如果这是您需要更改的唯一结尾行。 – theheadofabroom 2011-03-17 16:53:59

+4

@greg我会选择速度并使用'catalog = csv.reader(file.splitlines(),dialect = csv.excel_tab)'。 (csv阅读器可以接受一个字符串列表) – Calvin 2011-03-17 16:59:52

4

解决方案描述here应该工作。通过定义一个迭代器类,如下所示,它一次加载blob 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) 
+0

像一个魅力工作。非常感谢 – 2013-07-05 09:11:58

+1

在csv文件中,如果引用单元格,则可以在单个“单元格”中包含换行符。 splitlines()技术在这种情况下会中断。 – Troy 2015-01-28 08:54:49

相关问题