概述
從Selenium模塊化一文中,可以看出參數化的必要性,本文來介紹下讀取外部txt文件的方法。
如何打開文件
打開文件有以下兩個函數可以應用:
1、open(file_name,access_mode)
file_name: 文件路徑及名稱;
access_mode :訪問方式,具體參數如下,,未提供參數,則默認為r:
- r:表示讀取;
- w:表示寫入;
- a:表示添加;
- +: 表示讀寫;
- b:表示2進制訪問;
2、file函數
file()內建函數它的功能等於open(),如下根據文檔說明可知:
>>> help(open)
open(...)
open(name[, mode[, buffering]]) ->
file object
Open a file using the file() type, returns a file object. This is the
preferred way to open a file. See file.__doc__ for further information.(END)
讀取英文txt
接下來介紹讀取txt文件內容的方法,Python中提供了讀取文件的幾種方法,如下;
- Read() 讀取整個文件
- Readlines()按行讀取整個文件
- Readeline()按行讀取一行內容
現在假設讀取的txt文件存儲的是用戶登錄名及密碼的測試數據,內容如下:
admin,admin
guest,guest
test,test
那么這種情況就比較適合用按行讀取的方式來獲取文件,如下示例:
#coding:utf-8 import codecs def str_reader_txt(address): fp=open(address,'r') users=[] pwds=[] lines=fp.readlines() for data in lines: name,pwd=data.split(',') name=name.strip(' \t\r\n') pwd=pwd.strip(' \t\r\n') users.append(name) pwds.append(pwd) print "user:%s(len(%d))" %(name,len(name)) print "pwd:%s(len(%d))" %(pwd,len(pwd)) return users,pwds fp.close()
上述通過Readlines()按行讀取txt文件內容,並且使用split()函數切割字符串,分別得到用戶名和密碼,需要注意的是讀取出來的字符有最后面的回車符,所以需要strip函數進行過濾。
讀取中文txt
但是實際測試過程中,也有可能需要輸入中文的用戶及密碼,能否測試通過?修改測試文檔txt的用戶名為中文,內容如下:
管理員,admin
來賓,guest
測試人員,test
執行上述腳本后,結果如下:
可以看出,上述的腳本,在進行中文處理時,遇到異常,中文字符顯示亂碼,下面提供兩種解決方法:
方法一
#coding:utf-8 import codecs def str_reader_txt(address): fp=open(address,'r') users=[] pwds=[] lines=fp.readlines() for data in lines: print type(data) data=data.decode("gb18030")#處理中文編碼問題 print type(data) name,pwd=data.split(',') name=name.strip(' \t\r\n') pwd=pwd.strip(' \t\r\n') users.append(name) pwds.append(pwd) print "user:%s(len(%d))" %(name,len(name)) print "pwd:%s(len(%d))" %(pwd,len(pwd)) return users,pwds fp.close()
該方法是在分割內容之前,將代碼進行decode("gb18030")后,即可正常顯示,結果如下
原因說明
在python中提到unicode,一般指的是unicode對象,例如'哈哈'的unicode對象為 u'\u54c8\u54c8'
而str,是一個字節數組,這個字節數組表示的是對unicode對象編碼(可以是utf-8、gbk、cp936、GB2312)后的存儲的格式。這里它僅僅是一個字節流,沒有其它的含義,如果想使這個字節流顯示的內容有意義,就必須用正確的編碼格式,解碼顯示。
在上述腳本運行中,使用type(data)打印在decode前后的data的數據格式,如下:
<type 'str'>
<type 'unicode'>
可以看出,內置的open()方法打開文件時,read()讀取的是str格式的:
- Read()讀取時,如果參數是str(且內容中含有中文),讀取后需要使用正確的編碼格式進行decode(),轉為unicode字符后,才可以正確顯示。
- write()寫入時,如果參數是unicode,則需要使用你希望寫入的編碼進行encode(),如果是其他編碼格式的str,則需要先用該str的編碼進行decode(),轉成unicode后再使用寫入的編碼進行encode()。
方法二(推薦)
在文件打開時直接指定使用gb18030格式讀取后,即可直接操作,另外,該方法對中文txt和英文txt的處理均適用
#coding:utf-8 import codecs def str_reader_txt(address): fp=codecs.open(address,'r',"gb18030") #fp=open(address,'r') users=[] pwds=[] lines=fp.readlines() for data in lines: name,pwd=data.split(',') name=name.strip(' \t\r\n') pwd=pwd.strip(' \t\r\n') users.append(name) pwds.append(pwd) print "user:%s(len(%d))" %(name,len(name)) print "pwd:%s(len(%d))" %(pwd,len(pwd)) return users,pwds fp.close()
備注:Codecs.getreader也可以達到同樣的效果,如下:
#coding:utf-8 import codecs def str_reader_txt_csv(address): f=file(address,'rb') users=[] pwds=[] csv=codecs.getreader('gb18030')(f) #Codecs.getreaderf方法 for data in csv: name,pwd=data.split(',') name=name.strip(' \t\r\n') pwd=pwd.strip(' \t\r\n') users.append(name) pwds.append(pwd) return users,pwds f.close()
原因說明
模塊codecs提供了一個open()方法,可以指定一個編碼打開文件,使用這個方法打開的文件讀取返回的將是unicode。
寫入時,如果參數是unicode,則使用open()時指定的編碼進行編碼后寫入;
如果是str,則先根據源代碼文件聲明的字符編碼,解碼成unicode后再進行前述操作。對內置的open()來說,這個方法比較不容易在編碼上出現問題,推薦使用
為何使用gb18030的編碼格式
下面是通過對比測試的結果,可以看出使用gb18030和UTF-8操作的結果:
在windows平台下,默認的文檔保存方式為ANSI,在簡體中文系統下,ANSI 編碼代表 GB2312 編碼。
在txt保存時,修改保存格式為UTF-8時,可以使用UTF-8編碼打開,但是其字符長度有差異,其原因如下:
需要一提的是BOM(Byte Order Mark)。我們在儲存文件時,文件使用的編碼並沒有保存,打開時則需要我們記住原先保存時使用的編碼並使用這個編碼打開,這樣一來就產生了許多麻煩。
那記事本打開文件時並沒有讓選編碼?不妨先打開記事本再使用文件 -> 打開一個保存為UTF-8編碼格式的txt文檔看看
UTF引入了BOM來表示自身編碼,如果一開始讀入的幾個字節是其中之一,則代表接下來要讀取的文字使用的編碼是相應的編碼:
BOM_UTF8 '\xef\xbb\xbf'
BOM_UTF16_LE '\xff\xfe'
BOM_UTF16_BE '\xfe\xff'
那針對UTF-8格式文件存在BOM的情況下,如何獲取內容呢?Codec中有個方法codecs.BOM_UTF8可以去參考一下,此處不詳細解釋
GB2312、GBK、GB18030的區別及聯系
這里給出參考鏈接,http://www.zhihu.com/question/19677619
該文章描述的比較全面清晰,總結一下就是:
- GBK完全兼容GB2312
- GB 18030完全兼容GB 2312,基本兼容GBK,支持GB 13000及Unicode的全部統一漢字,共收錄漢字70244個。
GB 18030,全稱:國家標准GB 18030-2005《信息技術中文編碼字符集》,是中華人民共和國現時最新的內碼字集,是GB 18030-2000《信息技術信息交換用漢字編碼字符集基本集的擴充》的修訂版。
中文處理流程總結
處理中文數據時最好采用如下方式:
1. Decode early(盡早decode, 將文件中的內容轉化成unicode再進行下一步處理)
2. Unicode everywhere (程序內部處理都用unicode)
3. Encode late (最后encode回所需的encoding, 例如把最終結果寫進結果文件)
有幾點要說明一下:
* 所謂“正確的”編碼,指得是指定編碼和字符串本身的編碼必須一致。這個其實並不那么容易判斷,一般來說,我們直接輸入的簡體中文字符,有兩種可能的編碼:GB2312(GBK、GB18030)、以及UTF-8
* GB2312、GBK、GB18030本質上是同一種編碼標准。只是在前者基礎上擴充了字符數量
* UTF-8和GB編碼不兼容
*第二步,將str轉化為unicode對象時,可以使用下列兩個方法:都是將gb2312編碼的str轉為unicode編碼
- unicode(str,'gb2312')
- str.decode('gb2312')
*另外,在定義字符串時,出現中文,都使用str=u '漢字' 來定義。
參考資料
Python中文亂碼問題深入分析
http://www.jb51.net/article/26543.htm
http://www.cnblogs.com/huxi/archive/2010/12/05/1897271.html
詳解 python 中文編碼與處理
http://my.oschina.net/leejun2005/blog/74430
Python字符串的encode與decode研究心得——解決亂碼問題
http://blog.csdn.net/lxdcyh/article/details/4018054