2011-03-17 71 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

相關問題