(原創)python的字串讀寫和二進位制讀寫
阿新 • • 發佈:2019-01-02
python的文字讀寫和二進位制讀寫
筆者在之前的文件裡面提出過,scrapy框架本身存在大檔案下載的問題,因此產生了改造scrapy的想法,這裡在修改下載模組(FilesPipeline)的時候遇到了文字讀寫和二進位制讀寫的問題。
(scrapy具體bug見筆者的另外一兩部落格:scrapy的MemoryError(續),scrapy改造過程中踩過的坑(暫未發表))
上上週結束的時候,實驗室的師兄說組裡的爬蟲系統從應用市場裡爬取下來的PE檔案(exe和dll)無法再次上傳和下載,每次重新下載之後的檔案只有幾個k大小。我看了他的原始碼之後發現,其實也是因為字串讀導致上傳的時候發生了截斷。
字串讀寫和二進位制讀寫 :
python的檔案讀寫模組十分的方便,加上with as表示式這樣強大的工具,更是用幾行程式碼就可以完成檔案讀寫的功能。
with open('file.txt','rw') as f:
f.read()
#f.write('hello python')
其中open方法的第二個引數則是允許的檔案操作,一般來說為了檔案安全,遵循最小操作原則,即需要什麼操作,就僅允許哪類操作(《windows via c++》)
而我們今天要關注的是’b’這個關鍵詞,如果open的第二個引數不加’b’這個選項,則被判定為字串讀寫,否則視為二進位制讀寫。
這兩者是存在區別的(敲黑板):
二進位制讀是把整個檔案按照位元組進行讀取一直到檔案結束(EOF),不考慮其具體內容。
字串讀則是把檔案視為一個很長的字串,需要處理其中的換行符’\n’,結束符’\0’,轉義字元等問題。
問題程式碼復現:
最初的scrapy修改過程中的程式碼是這樣的:
class _ResponseReader(protocol.Protocol):
def __init__(self, finished, txresponse, request, maxsize, warnsize,
fail_on_dataloss,giant_file):
self._finished = finished
self._txresponse = txresponse
self._request = request
self._maxsize = maxsize
self._warnsize = warnsize
self._fail_on_dataloss = fail_on_dataloss
self._fail_on_dataloss_warned = False
self._reached_warnsize = False
self._bytes_received = 0
self._giant_file = giant_file
self.giant_file_path = ""
if giant_file==1:
# self._bodybuf = BytesIO()
self.giant_file_path = self.getabspath(self.file_path(request.url),request.store_path)
dir_name = os.path.dirname(self.giant_file_path)
if not os.path.exists(dir_name):
os.makedirs(dir_name)
f = open(self.giant_file_path,'w')
self._bodybuf = f
else:
self._bodybuf = BytesIO()
注意倒數第四行,這裡寫入檔案的方式是’w’,不是’wb’,因此遇到了PE檔案下載之後無法開啟,開啟之後報錯的問題。而修改方法就是改成’wb’。
而上面師兄的問題也是這樣的,在進行上傳的時候採用了’r’的讀入方式,而不是’rb’,這裡導致了下載的PE檔案只有幾個k,無法讀寫。