2010-06-03 89 views
7

我想知道是否有人更好地理解python和gae可以幫助我。我將一個csv文件從表單上傳到gae數據存儲區。用谷歌應用引擎上傳和解析csv文件

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')返回一個字符串。當迭代一個 字符串時,您將重複遍歷字符,而不是行。你可以看到 區別就在這裏:

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) 

我真的不遵循的解釋,並沒有成功實現它。任何人都可以提供更清晰的解釋和建議的修復嗎?

感謝,

回答

13

簡短的回答,試試這個:

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

朗的答案,考慮以下因素:

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

如果東西是一個文件指針,每一件事情是一條線。如果東西是一個列表,那麼每個東西都是一個項目。如果東西是一個字符串,每個東西都是一個字符。

對由csv.reader返回的對象進行迭代將給您的行爲類似於遍歷傳入的對象,僅對CSV解析的每個項目進行迭代。如果你遍歷一個字符串,你會得到每個字符的CSV解析版本。

+0

感謝您的解釋,現在對我來說更有意義。 – 2010-06-04 19:10:55

+0

我會考慮使用.splitlines()而不是.split('\ n') – 2012-03-13 01:46:38

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或者它如何處理附件)。

+0

謝謝!這解決了它,你的解釋讓我更容易理解。 – 2010-06-04 19:10:24

+0

@八月Flanagan我不認爲這個想法在句子中表達** Python csv模塊對文件類對象進行操作,這是一個文件或者像Python文件一樣的東西。因此,csv.reader()期望得到一個文件對象,因爲它只是必需的參數。**是正確的。文檔說__「csv.reader(csvfile,dialect ='excel',** fmtparams) 返回一個reader對象,它將迭代給定的csv文件中的行csvfile可以是任何支持迭代器協議的對象,並且每個對象都返回一個字符串它的next()方法被稱爲「_ – eyquem 2013-09-27 21:46:19

+0

@AugustFlanagan所以很顯然,''csv.reader(x)''在對象''x'上運行,不一定是文件類對象,唯一的要求是那''x''必須是可迭代的,並且在迭代時返回字符串。 – eyquem 2013-09-27 21:50:40

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) 
相關問題