今天準(zhǔn)備將某SQLite數(shù)據(jù)庫(kù)的內(nèi)容導(dǎo)出到文本文檔(*.txt)中,設(shè)計(jì)的Python程序如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | # -*- coding: UTF-8 -*- import sqlite3 def gsel(cur): cur.execute("SELECT * FROM collection") def main(): conn = sqlite3.connect("build.db3") cur = conn.cursor() gsel(cur) # conn.commit() rs = cur.fetchall() fp = open("output.txt", "w") for row in rs: fp.write(row[1]) # 讀取并寫入第2列數(shù)據(jù) if __name__ == '__main__': main() |
代碼上面應(yīng)該沒(méi)有什么問(wèn)題,Python使用的是版本2.7,但是在運(yùn)行的時(shí)候出現(xiàn)了異常錯(cuò)誤UnicodeEncodeError:
Traceback (most recent call last): File "makedb.py", line 33, inmain() File "makedb.py", line 30, in main fp.write(row[1]) UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-78: ordinal not in range(128)
本來(lái)以為數(shù)據(jù)讀取錯(cuò)誤,我特將fp.write改成print,結(jié)果數(shù)據(jù)全部讀取并顯示在命令控制臺(tái)上了,證明代碼是沒(méi)有問(wèn)題的,仔細(xì)看了下異常信息,貌似是因?yàn)榫幋a問(wèn)題:Unicode編碼與ASCII編碼的不兼容,其實(shí)這個(gè)Python腳本文件是由utf-8編碼的,同時(shí)SQlite3數(shù)據(jù)庫(kù)存取的也是UTF-8格式,Python默認(rèn)環(huán)境編碼通過(guò)下面的方法可以獲?。?/p>
import sys print sys.getdefaultencoding() # 'ascii' |
基本上是ascii編碼方式,由此Python自然調(diào)用ascii編碼解碼程序去處理字符流,當(dāng)字符流不屬于ascii范圍內(nèi),就會(huì)拋出異常(ordinal not in range(128))。
解決的方案很簡(jiǎn)單,修改默認(rèn)的編碼模式,很多朋友會(huì)想到setdefaultencoding,是的,我們可以通過(guò)sys.setdefaultencoding('utf-8′)來(lái)將當(dāng)前的字符處理模式修改為utf-8編碼模式,值得注意的是,如果單純這么調(diào)用的話,Python會(huì)拋出一個(gè)AttributeError異常:
Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'module' object has no attribute 'setdefaultencoding' |
竟然說(shuō)sys沒(méi)有setdefaultencoding的方法,其實(shí)sys是有這個(gè)方法的,但是要請(qǐng)出她老人家需要調(diào)用一次reload(sys),很奇怪,是么?如果有誰(shuí)知道原因的話,還望不吝賜教。
import sys reload(sys) sys.setdefaultencoding('utf-8') |
好了,通過(guò)上面短短的三行,我們算是很好的解決了這個(gè)問(wèn)題了,同樣的方式也可以應(yīng)用到UnicodeDecodeError上。當(dāng)然這個(gè)技巧來(lái)自于網(wǎng)絡(luò),我還找到其他特別的辦法,但是感覺還是這個(gè)比較靠譜,有童鞋說(shuō):我們將Python 2.x系列升級(jí)到Python 3.x系列就可以了,小小的問(wèn)題犯不著升級(jí)吧,畢竟2到3還是要有個(gè)過(guò)渡的。
最后,我將文章一開始的代碼更改如下:
# -*- coding: UTF-8 -*- import sys # 1 import sqlite3 def gsel(cur): cur.execute("SELECT * FROM collection") def main(): reload(sys) # 2 sys.setdefaultencoding('utf-8') # 3 conn = sqlite3.connect("build.db3") cur = conn.cursor() gsel(cur) # conn.commit() rs = cur.fetchall() fp = open("output.txt", "w") for row in rs: fp.write(row[1]) if __name__ == '__main__': main() |
看起來(lái),你這里的問(wèn)題,其實(shí)是:
把文件內(nèi)容,寫入到文件中時(shí),出錯(cuò)了。
而出錯(cuò)的原因其實(shí)是,python系統(tǒng),在使用默認(rèn)的編碼類型,此處的ascii,去將對(duì)應(yīng)的內(nèi)容,寫入到文件中。
但是由于其中一些內(nèi)容,ascii編碼不支持,所以報(bào)錯(cuò)。
所以,更好的辦法是,在輸出的時(shí)候,對(duì)文件制定特定的UTF-8編碼即可。
而無(wú)需改動(dòng)默認(rèn)編碼。
具體做法是:
不使用open打開文件,而使用codecs:
fp = codecs.open(‘output.txt’, ‘a(chǎn)+’, ‘utf-8′);;
fp.write(row[1]);
fp.close();