2014-10-04 95 views
3

我正在編寫一個腳本,它以遞歸方式掃描目錄並將它們存儲在作爲列表集合的字典中。該列表中包含具有文件名和文件大小的列表。該文件名可能包含UTF-8字符,如下所示。Python sqlite3.ProgrammingError:除非使用可解釋8位字節串的text_factory,否則不得使用8位字節串

['test.rus (\xd0\xa5\xd0\xb5\xd0\xbb\xd1\x8c\xd1\x88\xd0\xb8).srt', 23930] 
test.rus (Хельши).srt 

現在試圖插入數據到數據庫我得到如下錯誤

Traceback (most recent call last): 
    File "filedup.py", line 267, in <module> 
    read_file_directory(directory) 
    File "filedup.py", line 118, in read_file_directory 
    (values[i][0], each, values[i][1])) 
sqlite3.ProgrammingError: You must not use 8-bit bytestrings unless you use a text_factory that can interpret 8-bit bytestrings (like text_factory = str). It is highly recommended that you instead just switch your application to Unicode strings. 

其執行該操作的功能如下

from collections import defaultdict 
dirDict = defaultdict(list)  
def read_file_directory(path): 
    global dirDict 
    logger.debug("Path being scanned %s" %path) 
    fileStats = [] 
    for root, subFolders, files in os.walk(path): 
     for file_name in files: 
      fileStats = [] 
      fileStats.insert(0, file_name) 
      fileSize = os.path.getsize(os.path.join(root,file_name)) 
      fileStats.insert(1, fileSize) 
      dirDict[root].append(fileStats) 
    #Insert the data in DB 
    cursor = dbHandler.cursor() 
    keys = dirDict.keys() 
    for each in keys: 
     values = dirDict[each] 
     print values 
     for i in xrange(len(values)): 
      print values[i] 
      print values[i][0] 
      print values[i][1] 
      fileName = values[i][0] 
      fileSize = values[i][1] 
      cursor.execute("insert or ignore into master \ 
       (FileName, FilePath, FileSize) values(?,?,?)", \ 
       (values[i][0], each, values[i][1])) 
      logger.debug("Insert data for %s, %s, %s" %(values[i][0], each, values[i][1])) 

現在給出我想學習Python我沒有得到如何解決這個問題。我使用的Python版本低於

$ python 
Python 2.7.6 (default, Mar 22 2014, 22:59:56) 
[GCC 4.8.2] on linux2 

因此,任何想法如何與Python的當前版本修復,因爲我在尋找通用的修復,使其甚至可以在更高版本的工作中給出。 另外我觀察到,由於這個錯誤沒有數據被插入到數據庫中。那麼我怎樣才能確保即使某些操作導致的錯誤以前的數據可以插入到數據庫中。

+0

有你爲什麼使用UTF-8,而不是'unicode'什麼特別的原因? – 2014-10-04 13:49:18

+0

沒有理由我可以使用unicode也沒有任何問題。 – Abhinav 2014-10-04 13:57:32

+0

與你的實際問題無關,但'global dirDict'不是很好的風格。如果在調用read_file_directory()之前不需要'dirDict',在'read_file_directory()'中創建它,那麼最好將'dirDict'傳遞給函數,使得它的簽名變成'def read_file_directory(path,dirDict)', '並從該功能返回。 – mhawke 2014-10-04 14:21:56

回答

4

sqlite異常建議您切換到unicode字符串,所以你應該這樣做。

Python的目錄列表功能,如os.walk有一個curious property;當給定正常字符串時,它們將返回正常字符串,並在給定unicode字符串時返回unicode字符串。因此,在您的代碼中使用os.walk(path)時,應確保path是一個unicode字符串。

爲此,您可以使用unicode()函數明確轉換爲unicode,例如在致電os.walk之前編寫path = unicode(path)

另外,您需要在代碼中調用cursor.commit()才能真正寫入數據庫。在循環完所有文件名後調用一次就足夠了。

+0

如何確保路徑是一個unicode字符串。同時我可以繼續使用以下代碼 'cursor.execute(「插入或忽略到主\ (FileName,FilePath,FileSize)值(?,?,?)」,\ (values [i ] [0] .decode('utf-8'),each.decode('utf-8'),values [i] [1]))' 但是我想讓它unicode, t最終在其他錯誤 – Abhinav 2014-10-04 14:08:10

+0

@Ahhinav它取決於。你怎麼調用這個函數? – parchment 2014-10-04 14:12:19

+0

函數調用是 'read_file_directory(directory)' 該目錄將作爲參數的一部分傳遞給腳本。 – Abhinav 2014-10-04 14:19:12

2

嘗試改變行:

fileStats.insert(0, file_name) 

fileStats.insert(0, file_name.decode('utf8')) 
+0

我以其他方式完成,如下所示:cursor.execute(「insert或ignore into master \(FileName,FilePath,FileSize)values(?,?,?)」,\(values [i] [0] .decode ('utf-8'),each.decode('utf-8'),values [i] [1]))'那就行了。 – Abhinav 2014-10-04 14:30:33

+0

@Abhinav它可能工作,但它可能更好地轉換爲unicode儘可能早,這樣你就在內部處理unicode。 @parchment可能有一個關於使用unicode路徑作爲'os.walk()'參數的好處 - 你也應該檢查一下。 – mhawke 2014-10-04 14:36:36

+0

好的,我已經更新了代碼:'path = unicode(directory) read_file_directory(path)',並且它使用'decode('utf-8')'方法進行了處理。所有的值都會插入到數據庫中而不會出錯。 – Abhinav 2014-10-04 14:41:12

相關問題