檔案操作介紹
python中的都是用 open() 函數,調用 open() 函數,應用程式會發起系統調用 open(...) ,進而對檔案完成操作~。以下示例均在 python3 環境中完成~
讀取檔案
簡單讀取
讀取檔案示例:
f = open(file='/Users/luyi/tmp/abc', mode='r', encoding='utf-8')
data = f.read() # 讀取檔案中所有資料
print(data) # 列印檔案内容
f.close() # 關閉作業系統級打開的檔案
複制
open() 函數參數說明:
file:指定檔案路徑
mode:指定打開檔案的模式,r 表示隻讀模式,還有很多其他模式,下面會依次介紹
encoding:指定從檔案中讀取的資料使用什麼解碼标準(decode),解碼後以unicode的形式存放到記憶體中~。注意:若不指定encoding,打開檔案的預設編碼就是作業系統的預設編碼,簡體中文版的windows是gbk,linux下是utf-8。以什麼編碼存放,就應該以什麼編碼讀取~
複制
讀取檔案操作的注意點:
1)讀取動作完成之後,需要關閉作業系統級打開的檔案(f.close())
2)回收應用程式級的變量(del f)
Tip:f 變量沒有引用之後,python垃圾回收機制會自動回收 f 變量,無需手動進行。但是f.close()必須手動完成,否則會持續占用系統資源,直至程式運作結束~
也有一種方式 不需要手動關閉系統級資源
with open() as f:
pass
# 将上述代碼進行調整
with open(file = '/Users/luyi/tmp/abc', mode = 'r', encoding = 'utf-8') as f:
data = f.read()
print(data)
複制
Tip:with段代碼運作結束,系統級打開的檔案會自動被關閉~
with 還可以同時打開多個檔案,如下示例實作了檔案的檔案的逐行複制,其中涉及到的方法下面會介紹:
with open(file = '/Users/luyi/tmp/abc.txt', mode = 'r', encoding='utf-8') as read_file, open(file = '/Users/luyi/tmp/cde.txt', mode = 'w', encoding='utf-8') as write_file:
for line in read_file:
write_file.write(line)
複制
在讀取檔案時,若不清楚正在打開的檔案是什麼編碼,可以使用chardet子產品探測檔案的編碼方式
import chardet
result = chardet.detect(open('/Users/luyi/tmp/abc.txt', mode='rb').read())
print(result)
結果輸出:
{'encoding': 'utf-8', 'confidence': 0.87625, 'language': ''}
複制
上述示例中,使用 'rb' 模式打開檔案,即以隻讀,且以位元組為機關打開檔案。非文本檔案隻能使用 b 模式打開,因為檔案本身就是以位元組的形式存放在儲存設備上的。文本檔案可以使用位元組模式打開,也可以 以本文模式打開(預設),圖檔格式的檔案(jpg,png...)、視訊音頻格式檔案(mp3、mp4、avi...)則隻能以位元組模式打開。
當文本檔案使用位元組模式打開時,open函數中不能使用 encoding 參數,若要轉成unicode,隻能現将資料讀到記憶體,然後手動decode~
with open(file = '/Users/luyi/tmp/abc.txt', mode = 'rb', encoding = 'utf-8') as f:
print(f.read())
# open中使用 encoding參數,會直接抛出錯誤資訊
ValueError: binary mode doesn't take an encoding argument
#############
with open(file = '/Users/luyi/tmp/abc.txt', mode = 'rb') as f:
data = f.read()
print(data) # 原樣輸出内容
print(data.decode('utf-8')) # 解碼後輸出文本内容
輸出結果:
b'\xe4\xbd\xa0\xe5\xa5\xbd\xef\xbc\x8ckitty\n'
你好,kitty
複制
循環檔案
f = open("abc.txt",'r',encoding="utf-8")
data = f.read()
複制
使用這種方式讀取檔案,會一次性将檔案中所有的資料讀到記憶體中,如果檔案很大,這會給記憶體造成很大的壓力,這并不是一種合理的讀取檔案方式。這時候可以逐行擷取資料~
# 使用 readline() 僅讀取文本的一行内容,光标從檔案的開頭移動到一行的末尾(隻讀一行,遇到\r 或者 \n 為止),然後讀物第二行
with open(file = '/Users/luyi/tmp/def.txt', mode = 'r', encoding='utf-8') as f:
data = f.readline() # 僅讀取一行
print(data)
# 使用 while 循環周遊檔案
with open(file = '/Users/luyi/tmp/def.txt', mode = 'r', encoding='utf-8') as f:
line = f.readline()
while line: # 當 line 不為None,繼續讀取檔案
print(line, end='') # print() 自帶換行功能,line中已有'\n',print不用再換行,是以加上參數end=''
line = f.readline()
# 使用 for 循環周遊 f 變量也是逐行讀取檔案内容,與 readline() 類似。這裡其實内部調用了 f 變量的next()方法,逐行疊代檔案對象,這種方式的周遊貌似比 readline() 要來的簡單明了。
with open(file = '/Users/luyi/tmp/def.txt', mode = 'r', encoding='utf-8') as f:
for line in f:
print(line, end='')
複制
Tip:在調用next()方法時,不能同時調用 tell() 方法擷取檔案光标位置
和 readline() 功能類似的還有個 readlines() ,readlines()會将檔案的内容一次性擷取,并存儲為清單,檔案每一行内容為清單的一個元素~
with open(file = '/Users/luyi/tmp/def.txt', mode = 'r', encoding='utf-8') as f:
line = f.readlines()
print(type(line))
print(line)
結果輸出:
<class 'list'>
['1.aaaaaaaaa\n', '2.bbbbbbbbb\n', '3.ccccccccc\n', '4.ddddddddd\n', '5.eeeeeeeee\n', '6.fffffffff\n']
複制
寫檔案
python寫檔案,同樣使用open(),模式使用 'w'(隻寫),'wb'(二進制寫),'w+'(可讀可寫)~
直接寫
f = open(file = '/Users/luyi/tmp/abc.txt', mode = 'w', encoding = 'utf-8')
f.write('你好~~,hello')
f.close() # 同樣需要注意,關閉系統級别的資源
複制
open() 參數說明:
file:指定檔案路徑,若該目錄下檔案不存在,會建立,若檔案存在,直接覆寫;若目錄不存在,抛出錯誤
mode='w':指定為隻寫模式
encoding:指定寫入到檔案時,使用的編碼标準,即将 記憶體中 unicode 格式的資料 按照指定編碼标準編碼後進行存儲(這裡是 encoding 過程,和read相反)
複制
同樣可以使用 with open() 方式代替:
with open(file = '/Users/luyi/tmp/abc.txt', mode = 'w', encoding = 'utf-8') as f:
f.write('你好!!,hello')
複制
二進制寫
二進制寫 的模式為 'wb',當指定 mode='wb' ,寫入資料時必須傳入位元組類型的資料(bytes類型),且需要手動添加換行符(\n)
with open(file = '/Users/luyi/tmp/abc.txt', mode = 'wb') as f:
f.write('你好~~,hello'.encode('utf-8'))
複制
Tip:這裡由于是'wb'模式,write()函數中需要傳入bytes類型的資料,直接使單引号或雙引号包含的資料是 str 類型,str 類型的資料 encode 之後,傳回的是 bytes類型,或者也可以使用 b'' ~
with open(file = '/Users/luyi/tmp/abc.txt', mode = 'wb') as f:
f.write(b'abc') # bytes 類型隻能包含 ASCII 碼字元
複制
同時寫入多行使用writelines()函數
with open(file = '/Users/luyi/tmp/abc.txt', mode = 'w', encoding='utf-8') as f:
f.writelines(['111111\n', '222222\n', '333333\n']) # 需要自己添加換行符
# wb模式
with open(file = '/Users/luyi/tmp/abc.txt', mode = 'wb') as f:
f.writelines([bytes('你好\n'.encode('utf-8')), 'kitty\n'.encode('utf-8')])
複制
Tip:f.flush() 可立刻将檔案内容從記憶體刷到磁盤
注意點:當以 'w' 、'wb'、'w+'(寫讀模式,很少用) 模式打開檔案時,在打開檔案的同時會将檔案内容清空~
讀寫模式
打開檔案模式還有讀寫模式,打開後可進行讀寫操作,即 mode='r+';
with open(file = '/Users/luyi/tmp/abc.txt', mode = 'r+', encoding='utf-8') as f:
print(f.read())
f.write('你好~~,hello')
複制
追加檔案
打開檔案時,若使用模式 “a” 或 “ab” ,則隻能對檔案進行追加,即:在原來内容的尾部追加内容~
with open(file = '/Users/luyi/tmp/abc.txt', mode = 'a', encoding='utf-8') as f:
f.write('aaaaaaa\n')
f.write('vvvvvvv\n')
檔案内容:
你好
kitty
aaaaaaa
vvvvvvv
複制
檔案操作的各種模式說明
操作檔案的模式列舉
模式 | 說明 |
---|---|
'r' | 讀模式 |
'w' | 寫模式 |
'a' | 追加模式 |
'b' | 二進制模式 |
't' | text 模式(預設) |
'+' | 同時讀寫某個檔案 |
'x' | 隻寫模式,檔案不存在 自動建立,檔案原先就存在則報錯 |
除了上述幾個模式,還有以上模式的各種組合~
常用的模式還有:
rb','wb','ab' # 非文本檔案,隻能使用 'b' 模式打開
'r+','w+','a+' # 都表示可讀寫,但是注意了 'w+' 模式打開檔案,會首先清空檔案,是以一般模式 'w+' 很少用,使用模式 'a+' 時,光标會直接跳到檔案的最後,是以之前的内容讀不到~
針對檔案的其他操作
其他檔案操作的常用函數:
def writable(self, *args, **kwargs): # real signature unknown
判斷檔案是否可寫
def readable(self, *args, **kwargs): # real signature unknown
判斷檔案是否可讀
def fileno(self, *args, **kwargs): # real signature unknown
傳回檔案句柄在核心中的索引值,做IO多路複用時可以用到
def seek(self, *args, **kwargs): # real signature unknown
移動光标移到指定位置,注意這裡移動光标的機關是位元組
def seekable(self, *args, **kwargs): # real signature unknown
判斷檔案是否可進行 seek 操作
def tell(self, *args, **kwargs): # real signature unknown
傳回目前檔案操作光标位置
def truncate(self, *args, **kwargs): # real signature unknown
按指定長度截斷檔案,經個人測試 python3中的 truncate 方法貌似已經失效
複制
在對檔案操作的過程中,光标會不斷移動,例如readline()方法讀取一行資訊後,光标會移動至目前行的末尾,writeline()光标也會移動至目前行末尾(寫過程貌似光标一直在末尾)~
光标移動的機關和檔案被打開的模式相關,若檔案以文本模式打開時,read(5) 會使光标向後移動5個字元;若檔案以非文本模式打開('b'模式),則 read() 會向後移動5個位元組。seek函數不管模式是什麼,光标移動的機關都是位元組~
例如文本内容如下:
123456789
abcdefghi
複制
code:
with open(file = '/Users/luyi/tmp/abc.txt', mode = 'r+', encoding='utf-8') as f:
f.seek(5)
print(f.readline())
print(f.tell()) # 輸出目前光标位置
結果輸出:
6789
10
複制
seek 方法可接受2個參數:
fileObject.seek(offset[, whence])
複制
offset:光标的偏移量,以位元組為機關
whence:可選參數,預設值為 0。表示要從哪個位置開始偏移;0 代表從檔案開頭開始偏移,1 代表從目前位置開始偏移,2 代表從檔案末尾開始偏移。
.................^_^