2011-03-17 46 views
9

python'da "evrensel yeni satır" ile csv dosyasını yükle ve ayrıştırma GAE'de bir formdan bir csv/tsv dosyası yüklüyorum ve dosyayı python csv modülü ile ayrıştırmaya çalışıyorum.Google App Engine

here tanımındaki gibi, GAE dosyasında yüklenen dosyalar dizgilerdir.
Ben de yüklenen dize bir dosya benzeri bir nesne tedavi:

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

Ama dosyalarında yeni hatlar mutlaka '\ n' (teşekkürler .. excel) yoktur ve bu bir hata oluşturulur:
Hata: Satılamayan alanda görülen yeni satır karakteri - dosyayı evrensel yeni satır modunda açmanız mı gerekiyor?

Evrensel yeni satırda açılan dosyalar gibi dizeleri işlemek için StringIO.StringIO'nun nasıl kullanılacağını bilen var mı? yaklaşık

+0

Python Docs göre StringIO varsayılan modu evrensel satır olduğunu. Veri dosyanızda bir şey yabancı olabilir. – Calvin

+0

@Calvin _ "Python belgelerine göre, StringIO'nun varsayılan modu evrensel yeni hattır" _ Dokümanların nerede olduğunu söyleyemedim, gösterebilir miyiz lütfen? – eyquem

+0

@eyquem 2,5 yıl geçti, bu yüzden dokümanlar değişmiş olabilir, ancak http://docs.python.org/3.3/library/io.html?highlight=stringio#io.StringIO, 'Yeni satır argümanı TextIOWrapper'ınki gibi çalışır 've TextIOWrapper' yeni satırın Yok ise, evrensel yeni satırlar modu etkin 'diyor. Ama sonra StringIO, 'Varsayılan olarak yeni satır çevirisi yapmamak' diyerek bununla çelişir. – Calvin

cevap

5

Nasıl:

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

veya

Açıklamalarda belirttiği, csv.reader() yüzden, bir listeden girişi destekler: Gelecekteki request.get desteklerde
file = self.request.get('catalog') 
catalog = csv.reader(file.splitlines(),dialect=csv.excel_tab) 

veya eğer

modlarını okuyun:

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

Aslında .splitlines() kullanıyorum ama çok büyük dosyalarda çalışıyorum ve çok hızlı değil. request.get() okuma modlarını desteklemiyor. – greg

+1

@greg: Öyleyse sıkışmışsın. Değiştirmeniz gereken bitiş çizgisi buysa, .replace ('\ r \ n', '\ n') yaparak öykünebilirsiniz. – theheadofabroom

+4

@greg Hız isabeti alıyorum ve 'catalog = csv.reader (file.splitlines(), dialect = csv.excel_tab)' komutunu kullanıyorum. (csv okuyucu dizelerin bir listesini kabul edebilir) – Calvin

4

here açıklanan çözüm çalışması gerekir. Her defasında bloğun 1MB'yi yükleyen bir yineleyici sınıfını tanımlayarak, .splitlines() kullanarak satırları ayırır ve daha sonra satırları CSV okuyucusuna birer birer besler, tüm satırlar tüm dosyayı yüklemeye gerek kalmadan işlenebilir belleğe.

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 

Sonra şöyle diyoruz:

blob_reader = blobstore.BlobReader(blob_key) 
blob_iterator = BlobIterator(blob_reader) 
reader = csv.reader(blob_iterator) 
+0

bir çekicilik gibi çalıştı. Çok teşekkürler –

+1

Csv dosyalarında, hücre alıntı varsa, tek bir "hücre" içinde satırsonu karakterleri olabilir. Bu senaryoda splitlines() tekniği kırılacaktır. – Troy