1. 程式人生 > >(原創)python的字串讀寫和二進位制讀寫

(原創)python的字串讀寫和二進位制讀寫

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,無法讀寫。