2011-03-17 27 views
9

Tôi đang tải lên tệp csv/tsv từ một biểu mẫu trong GAE và tôi cố gắng phân tích tệp bằng mô-đun csv python.Tải lên và phân tích cú pháp tệp csv bằng "dòng mới phổ quát" trong python trên Google App Engine

Giống như mô tả here, tệp được tải lên trong GAE là các chuỗi.
Vì vậy, tôi đối xử với tôi tải lên chuỗi một đối tượng tập tin giống như:

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

Nhưng dòng mới trong các tập tin của tôi không nhất thiết phải '\ n' (nhờ trội ..), và nó tạo ra một lỗi:
Lỗi: ký tự dòng mới được nhìn thấy trong trường không được đánh dấu - bạn có cần mở tệp ở chế độ phổ-newline không?

Có ai biết cách sử dụng StringIO.StringIO để xử lý các chuỗi như tệp mở trong dòng chung-new không?

+0

Theo các tài liệu Python, chế độ mặc định StringIO là newline phổ quát. Một người lạ có thể đang diễn ra trong tệp dữ liệu của bạn. – Calvin

+0

@Calvin _ "Theo tài liệu Python, chế độ mặc định của StringIO là dòng mới phổ quát" _ Tôi không tìm thấy tài liệu nói điều đó ở đâu, có thể hiển thị nó không? – eyquem

+0

@eyquem Đã được 2,5 năm, vì vậy tài liệu có thể đã thay đổi, nhưng http://docs.python.org/3.3/library/io.html?highlight=stringio#io.StringIO nói 'Đối số dòng mới hoạt động giống như của TextIOWrapper 'và TextIOWrapper nói' nếu dòng mới là Không, chế độ dòng mới phổ quát được bật. ' Nhưng sau đó StringIO có thể mâu thuẫn với điều này bằng cách nói 'Mặc định là không làm bản dịch mới.' – Calvin

Trả lời

5

Làm thế nào về:

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

hoặc như đã chỉ ra trong các ý kiến, csv.reader() hỗ trợ đầu vào từ một danh sách, vì vậy:

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

hoặc nếu trong request.get hỗ trợ trong tương lai đọc chế độ:

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

Tôi thực sự sử dụng .splitlines() nhưng tôi làm việc trên các tập tin rất lớn và nó không phải là rất nhanh. request.get() không hỗ trợ chế độ đọc. – greg

+1

@greg: Sau đó, bạn bị mắc kẹt. Bạn có thể mô phỏng nó bằng cách thực hiện .replace ('\ r \ n', '\ n') nếu đó là dòng duy nhất kết thúc bạn cần thay đổi. – theheadofabroom

+4

@greg Tôi sẽ lấy tốc độ truy cập và sử dụng 'catalog = csv.reader (file.splitlines(), phương ngữ = csv.excel_tab)'. (csv đọc có thể chấp nhận một danh sách các chuỗi) – Calvin

4

Giải pháp được mô tả here sẽ hoạt động. Bằng cách định nghĩa một lớp lặp như sau, tải blob 1MB tại một thời điểm, chia tách các dòng bằng cách sử dụng .splitlines() và sau đó nạp các dòng vào đầu đọc CSV cùng một lúc, các dòng mới có thể được xử lý mà không phải tải toàn bộ tệp vào bộ nhớ.

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 

Sau đó gọi đây là như vậy:

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

hoạt động như một sự quyến rũ. Cảm ơn rất nhiều –

+1

Trong tệp csv, bạn có thể có ký tự dòng mới trong một "ô" duy nhất, nếu ô được trích dẫn. Kỹ thuật splitlines() sẽ phá vỡ trong kịch bản đó. – Troy

Các vấn đề liên quan