day8_文件操作及編碼解碼
一、文件操作基本流程
計算機系統分為:計算機硬件,操作系統,應用程序三部分。
我們用python或其他語言編寫的應用程序若想要把數據永久保存下來,必須要保存於硬盤中,這就涉及到應用程序要操作硬件,眾所周知,應用程序是無法直接操作硬件的,這就用到了操作系統。操作系統把復雜的硬件操作封裝成簡單的接口給用戶/應用程序使用,其中文件就是操作系統提供給應用程序來操作硬盤虛擬概念,用戶或應用程序通過操作文件,可以將自己的數據永久保存下來。
有了文件的概念,我們無需再去考慮操作硬盤的細節,只需要關註操作文件的流程:
#1. 打開文件,得到文件句柄並賦值給一個變量 f=open(‘a.txt‘,‘r‘,encoding=‘utf-8‘) #默認打開模式就為r #2. 通過句柄對文件進行操作 data=f.read() #3. 關閉文件 f.close()
關閉文件的註意事項:
打開一個文件包含兩部分資源:操作系統級打開的文件+應用程序的變量。在操作完畢一個文件時,必須把與該文件的這兩部分資源一個不落地回收,回收方法為:
1 f.close() #回收操作系統級打開的文件 2 del f #回收應用程序級的變量
其中del f一定要發生在f.close()之後,否則就會導致操作系統打開的文件還沒有關閉,白白占用資源,
而python自動的垃圾回收機制決定了我們無需考慮del f,這就要求我們,在操作完畢文件後,一定要記住f.close()
雖然我這麽說,但是很多同學還是會很不要臉地忘記f.close(),對於這些不長腦子的同學,我們推薦傻瓜式操作方式:使用with關鍵字來幫我們管理上下文
with open(‘a.txt‘,‘w‘) as f: pass with open(‘a.txt‘,‘r‘) as read_f,open(‘b.txt‘,‘w‘) as write_f: data=read_f.read() write_f.write(data)
二、文件編碼
f=open(...)是由操作系統打開文件,那麽如果我們沒有為open指定編碼,那麽打開文件的默認編碼很明顯是操作系統說了算了,操作系統會用自己的默認編碼去打開文件,在windows下是gbk,在linux下是utf-8。
#這就用到了上節課講的字符編碼的知識:若要保證不亂碼,文件以什麽方式存的,就要以什麽方式打開。 f=open(‘a.txt‘,‘r‘,encoding=‘utf-8‘)
三、文件的打開模式
文件句柄 = open(‘文件路徑’,‘模式’)
#1. 打開文件的模式有(默認為文本模式): r ,只讀模式【默認模式,文件必須存在,不存在則拋出異常】 w,只寫模式【不可讀;不存在則創建;存在則清空內容】 a, 只追加寫模式【不可讀;不存在則創建;存在則只追加內容】 #2. 對於非文本文件,我們只能使用b模式,"b"表示以字節的方式操作(而所有文件也都是以字節的形式存儲的,使用這種模式無需考慮文本文件的字符編碼、圖片文件的jgp格式、視頻文件的avi格式) rb wb ab 註:以b方式打開時,讀取到的內容是字節類型,寫入時也需要提供字節類型,不能指定編碼 #3,‘+’模式(就是增加了一個功能) r+, 讀寫【可讀,可寫】 w+,寫讀【可寫,可讀】 a+, 寫讀【可寫,可讀】 #4,以bytes類型操作的讀寫,寫讀,寫讀模式 r+b, 讀寫【可讀,可寫】 w+b,寫讀【可寫,可讀】 a+b, 寫讀【可寫,可讀】
四、文件操作方法
4.1常用操作方法
red(3):
1、文件打開方式為文本模式時,代表讀取3個字符;
2、文件打開方式為b模式時,代表讀取3個字節。
其余的文件內光標移動都是以字節為單位的:sekk,tell,truncate(截取文件的一部分)
註意:
1、seek有三種移動方式0,1,2,其中1和2必須在b模式下進行,但無論哪種模式,都是以bytes為單位移動。
file.seek()方法標準格式是:file.seek(offset,whence)
offset:開始的偏移量,也就是代表需要移動偏移的字節數
whence:給offset參數一個定義,表示要從哪個位置開始偏移;0代表從文件開頭開始算起,1代表從當前位置開始算起,2代表從文件末尾算起。whence值為空沒設置時會默認為0。
2、truncate是截斷文件,文件打開的方式必須是可寫,但不能用w或者w+方式打開,因為會直接清空文件。故,truncate必須在r+或者a或者a+的模式下使用。
4.2 所有操作方法
class TextIOWrapper(_TextIOBase): """ Character and line based layer over a BufferedIOBase object, buffer. encoding gives the name of the encoding that the stream will be decoded or encoded with. It defaults to locale.getpreferredencoding(False). errors determines the strictness of encoding and decoding (see help(codecs.Codec) or the documentation for codecs.register) and defaults to "strict". newline controls how line endings are handled. It can be None, ‘‘, ‘\n‘, ‘\r‘, and ‘\r\n‘. It works as follows: * On input, if newline is None, universal newlines mode is enabled. Lines in the input can end in ‘\n‘, ‘\r‘, or ‘\r\n‘, and these are translated into ‘\n‘ before being returned to the caller. If it is ‘‘, universal newline mode is enabled, but line endings are returned to the caller untranslated. If it has any of the other legal values, input lines are only terminated by the given string, and the line ending is returned to the caller untranslated. * On output, if newline is None, any ‘\n‘ characters written are translated to the system default line separator, os.linesep. If newline is ‘‘ or ‘\n‘, no translation takes place. If newline is any of the other legal values, any ‘\n‘ characters written are translated to the given string. If line_buffering is True, a call to flush is implied when a call to write contains a newline character. """ def close(self, *args, **kwargs): # real signature unknown 關閉文件 pass def fileno(self, *args, **kwargs): # real signature unknown 文件描述符 pass def flush(self, *args, **kwargs): # real signature unknown 刷新文件內部緩沖區 pass def isatty(self, *args, **kwargs): # real signature unknown 判斷文件是否是同意tty設備 pass def read(self, *args, **kwargs): # real signature unknown 讀取指定字節數據 pass def readable(self, *args, **kwargs): # real signature unknown 是否可讀 pass def readline(self, *args, **kwargs): # real signature unknown 僅讀取一行數據 pass def seek(self, *args, **kwargs): # real signature unknown 指定文件中指針位置 pass def seekable(self, *args, **kwargs): # real signature unknown 指針是否可操作 pass def tell(self, *args, **kwargs): # real signature unknown 獲取指針位置 pass def truncate(self, *args, **kwargs): # real signature unknown 截斷數據,僅保留指定之前數據 pass def writable(self, *args, **kwargs): # real signature unknown 是否可寫 pass def write(self, *args, **kwargs): # real signature unknown 寫內容 pass def __getstate__(self, *args, **kwargs): # real signature unknown pass def __init__(self, *args, **kwargs): # real signature unknown pass @staticmethod # known case of __new__ def __new__(*args, **kwargs): # real signature unknown """ Create and return a new object. See help(type) for accurate signature. """ pass def __next__(self, *args, **kwargs): # real signature unknown """ Implement next(self). """ pass def __repr__(self, *args, **kwargs): # real signature unknown """ Return repr(self). """ pass buffer = property(lambda self: object(), lambda self, v: None, lambda self: None) # default closed = property(lambda self: object(), lambda self, v: None, lambda self: None) # default encoding = property(lambda self: object(), lambda self, v: None, lambda self: None) # default errors = property(lambda self: object(), lambda self, v: None, lambda self: None) # default line_buffering = property(lambda self: object(), lambda self, v: None, lambda self: None) # default name = property(lambda self: object(), lambda self, v: None, lambda self: None) # default newlines = property(lambda self: object(), lambda self, v: None, lambda self: None) # default _CHUNK_SIZE = property(lambda self: object(), lambda self, v: None, lambda self: None) # default _finalizing = property(lambda self: object(), lambda self, v: None, lambda self: None) # default 3.x 3.xView Code
五、文件的修改
文件的數據是存放於硬盤上的,因而只存在覆蓋、不存在修改這麽一說,我們平時看到的修改文件,都是模擬出來的效果,具體的說有兩種實現方式:
方式一:將硬盤存放的該文件的內容全部加載到內存,在內存中是可以修改的,修改完畢後,再由內存覆蓋到硬盤(word,vim,nodpad++等編輯器)
import os # 調用系統模塊 with open(‘a.txt‘) as read_f,open(‘.a.txt.swap‘,‘w‘) as write_f: data=read_f.read() #全部讀入內存,如果文件很大,會很卡 data=data.replace(‘alex‘,‘SB‘) #在內存中完成修改 write_f.write(data) #一次性寫入新文件 os.remove(‘a.txt‘) #刪除原文件 os.rename(‘.a.txt.swap‘,‘a.txt‘) #將新建的文件重命名為原文件
方式二:將硬盤存放的該文件的內容一行一行地讀入內存,修改完畢就寫入新文件,最後用新文件覆蓋源文件
import os with open(‘a.txt‘) as read_f,open(‘.a.txt.swap‘,‘w‘) as write_f: for line in read_f: line=line.replace(‘alex‘,‘SB‘) write_f.write(line) os.remove(‘a.txt‘) os.rename(‘.a.txt.swap‘,‘a.txt‘)
六、編碼解碼
#str --->byte encode 編碼 s = ‘二哥‘ b = s.encode(‘utf-8‘) print(b) # byte --->str decode 解碼 s1 = b.decode(‘utf-8‘) print(s1) s = ‘abf‘ b = s.encode(‘utf-8‘) print(b) # #byte --->str decode 解碼 s1 = b.decode(‘gbk‘) print(s1)
七、當日練習
1. 文件a.txt內容:每一行內容分別為商品名字,價錢,個數。
apple 10 3
tesla 100000 1
mac 3000 2
lenovo 30000 3
chicken 10 3
通過代碼,將其構建成這種數據類型:[{‘name‘:‘apple‘,‘price‘:10,‘amount‘:3},{‘name‘:‘tesla‘,‘price‘:1000000,‘amount‘:1}......] 並計算出總價錢。
2,有如下文件:
-------
alex是老男孩python發起人,創建人。
alex其實是人妖。
誰說alex是sb?
你們真逗,alex再牛逼,也掩飾不住資深屌絲的氣質。
----------
將文件中所有的alex都替換成大寫的SB。
day8_文件操作及編碼解碼