使用谷歌应用引擎上传和解析csv文件

时间:2010-06-03 23:48:13

标签: python google-app-engine csv

我想知道是否有人对python和gae有更好的理解可以帮助我解决这个问题。我正在将一个csv文件从表单上传到gae数据存储区。

class CSVImport(webapp.RequestHandler):
  def post(self):
     csv_file = self.request.get('csv_import')
     fileReader = csv.reader(csv_file)
     for row in fileReader:       
       self.response.out.write(row) 

我遇到了其他人在这里提到的问题 - http://groups.google.com/group/google-appengine/browse_thread/thread/bb2d0b1a80ca7ac2/861c8241308b9717

也就是说,csv.reader迭代每个字符而不是行。一位谷歌工程师留下了这个解释:

  

调用self.request.get('csv')返回一个String。当你迭代一个   字符串,你迭代字符,而不是行。你可以看到   区别在于:

 class ProcessUpload(webapp.RequestHandler): 
   def post(self): 
     self.response.out.write(self.request.get('csv')) 
     file = open(os.path.join(os.path.dirname(__file__), 'sample.csv')) 
     self.response.out.write(file) 

     # Iterating over a file 
     fileReader = csv.reader(file) 
     for row in fileReader: 
       self.response.out.write(row) 

     # Iterating over a string 
     fileReader = csv.reader(self.request.get('csv')) 
     for row in fileReader: 
       self.response.out.write(row) 

我真的不遵循解释,并且没有成功实施。任何人都可以提供更明确的解释和建议的解决方案吗?

谢谢, 八月

3 个答案:

答案 0 :(得分:13)

简短回答,试试这个:

fileReader = csv.reader(csv_file.split("\n"))

答案很长,请考虑以下事项:

for thing in stuff:
  print thing.strip().split(",")

如果stuff是文件指针,则每个东西都是一行。如果stuff是一个列表,那么每个东西都是一个项目。如果stuff是一个字符串,那么每个东西都是一个字符。

迭代csv.reader返回的对象将给你类似于迭代传入的对象的行为,只对每个CSV解析的项目。如果您遍历一个字符串,您将获得每个字符的CSV解析版本。

答案 1 :(得分:8)

我想不出比你提到的谷歌工程师所说的更明确的解释。所以让我们稍微分解一下。

Python csv模块对类似文件的对象进行操作,即文件或行为类似于Python文件的对象。因此,csv.reader()希望得到一个文件对象,因为它只是必需的参数。

webapp.RequestHandler请求对象提供对表单中发布的HTTP参数的访问。在HTTP中,参数作为键值对发布,例如csv=record_one,record_two。当您调用self.request.get('csv')时,这将返回与密钥csv关联的作为Python字符串。 Python字符串不是类文件对象。显然,当csv模块不理解对象并简单地迭代它时,它就会回落(在Python中,字符串可以按字符迭代,例如,for c in 'Test String': print c将打印字符串中的每个字符在另一条线上。)

幸运的是,Python提供了一个StringIO类,它允许将字符串视为类文件对象。所以(假设GAE支持StringIO,并且没有理由不应该这样做)你应该能够做到这一点:

class ProcessUpload(webapp.RequestHandler): 
   def post(self): 
     self.response.out.write(self.request.get('csv')) 

     # Iterating over a string as a file 
     stringReader = csv.reader(StringIO.StringIO(self.request.get('csv')))
     for row in stringReader: 
        self.response.out.write(row) 

哪个会按预期工作。

编辑我假设您使用类似<textarea/>的内容来收集csv文件。如果您正在上传附件,可能需要进行不同的处理(我不熟悉Python GAE或它如何处理附件)。

答案 2 :(得分:0)

您需要致电csv_file = self.request.POST.get("csv_import") csv_file = self.request.get("csv_import")

第二个只是给你一个你在原帖中提到的字符串。但是,通过self.request.POST.get访问会为您提供cgi.FieldStorage个对象。

这意味着您可以调用csv_file.filename来获取对象的文件名,并调用csv_file.type来获取mimetype。 此外,如果您访问csv_file.file,它是一个StringO对象(来自StringIO module的只读对象),而不仅仅是一个字符串。正如his answer中提到的ig0774,StringIO模块允许您将字符串视为文件。

因此,您的代码可以简单地为:

class CSVImport(webapp.RequestHandler):
  def post(self):
     csv_file = self.request.POST.get('csv_import')
     fileReader = csv.reader(csv_file.file)
     for row in fileReader:
       # row is now a list containing all the column data in that row
       self.response.out.write(row)