python 檔案處理
一、概述
資料的儲存可以使用資料庫,也可以使用檔案。
資料庫保持了資料的完整性和關聯性,且使用資料更安全、可靠。使用檔案儲存資料則非常簡單、易用,不必安裝資料庫管理系統等執行環境。
檔案通常用於儲存應用軟體的引數或臨時性資料,是一個命名的位元集合,儲存在硬碟、U盤、快閃記憶體條等輔助儲存裝置中。
檔案分為兩類:文字檔案和二進位制檔案。 Python提供了os、os.path、shutil等模組處理檔案。
文字檔案的特點:
基本是字串。Python原始碼檔案和HTML檔案等都屬於文字檔案。
可使用任何文字編輯器進行編輯,對人來說相對容易閱讀和修改。
對程式來說,無法直接閱讀文字檔案。通常,每種文字檔案都需要使用相應的分析程式來閱讀,例如,Python使用專用分析程式來幫助閱讀.py檔案,而要閱讀HTML檔案,需要使用專用於HTML的分析程式。
通常比等價的二進位制檔案大。需要通過網路傳送大型文字檔案時,一般要進行壓縮(如壓縮成zip格式),以提高傳輸速度和節省磁碟空間。
二進位制檔案的特點:
通常是人無法直接閱讀的,且使用常規的文字編輯器無法檢視。在文字編輯器中開啟二進位制檔案時,顯示的是一堆亂碼。有些型別的二進位制檔案(如JPEG影象)需要使用特殊檢視器顯示其內容。
佔據的空間通常比等價的文字檔案小。
對程式來說,可以直接閱讀二進位制檔案。雖然二進位制檔案各不相同,但通常無需編寫複雜的分析程式來讀取它們。
二、檔案的常見操作
- 開啟檔案: 建立磁碟上的檔案與程式中的物件相關聯 ;通過相關的檔案物件獲得
- 檔案操作: 讀取、寫入 複製、刪除 ;定位; 其他:追加、計算等
- 關閉檔案 :切斷檔案與程式的聯絡; 寫入磁碟,並釋放檔案緩衝區
1、檔案的建立
檔案的開啟或建立可以使用open函式。該函式可以指定處理模式,設定開啟的檔案為只讀、只寫或可讀寫狀態。
格式1: open(file, [mode[, buffering]])—>file object
格式2:with open(file, [mode[, buffering]]) as file object name
- 引數file是被開啟的檔名。若檔案file不存在,open()將建立該檔案,然後再開啟該檔案。
- 引數mode是指檔案的開啟模式(預設r)。開啟模式如表8-1。
- 引數buffering設定快取模式。0表示無緩衝;1表示行緩衝;如果大於1則表示緩衝區的大小,,-1(或者任何負數,預設為-1)代表使用預設的緩衝區大小。以位元組為單位。
- open()返回1個file物件,file物件可以對檔案進行各種操作。
引數 |
描述 |
r |
只讀模式,如果檔案不存在,返回異常FileNotFoundError,預設值 |
w |
覆蓋寫模式,檔案不存在則建立,存在則完全覆蓋 |
x |
建立寫模式,檔案不存在則建立,存在則返回異常FileExistsError |
a |
追加寫模式,檔案不存在則建立,存在則在檔案最後追加內容 |
t |
文字檔案模式,預設值 |
b |
二進位制檔案模式,可與r/w/x/a/+結合使用 |
+ |
與r/w/x/a一同使用,在原功能基礎上增加同時讀寫功能 |
U |
支援所有的換行符號。如:’\r’、’\n’、’\r\n’ |
file類用於檔案管理,可以對檔案進行建立、開啟、讀寫、關閉等操作。
檔案的處理一般分為三個步驟:
- 建立並開啟檔案,使用open()函式返回1個file物件。
- 呼叫file物件的read()、write()等方法處理檔案。
- 呼叫close()關閉檔案,釋放file物件佔用的資源(若使用格式2,可省略此步驟)。
file類的常用屬性和方法
屬性和方法 |
描述 |
closed |
判斷檔案是否關閉,如果檔案關閉,返回True |
encoding |
顯示檔案的編碼型別 |
mode |
顯示檔案的開啟模式 |
name |
顯示檔案的名稱 |
newlines |
檔案使用的換行模式 |
flush() |
將緩衝區的內容寫入磁碟 |
close() |
關閉檔案 |
read([size]) |
從檔案中讀取size個位元組的內容,作為字串返回;預設返回包含整個檔案內容的一個字串 |
readline([size]) |
從檔案中讀取1行,作為字串返回。若指定size,表示每行每次讀取的位元組數,依然要讀完整行的內容 |
readlines([size]) |
返回值為整個檔案內容的列表,每項是以換行符為結尾的一行字串。若指定size,表示每次讀取的位元組數 |
屬性和方法 |
描述 |
closed |
判斷檔案是否關閉,如果檔案關閉,返回True |
encoding |
顯示檔案的編碼型別 |
mode |
顯示檔案的開啟模式 |
name |
顯示檔案的名稱 |
newlines |
檔案使用的換行模式 |
flush() |
將緩衝區的內容寫入磁碟 |
close() |
關閉檔案 |
read([size]) |
從檔案中讀取size個位元組的內容,作為字串返回;預設返回包含整個檔案內容的一個字串 |
readline([size]) |
從檔案中讀取1行,作為字串返回。若指定size,表示每行每次讀取的位元組數,依然要讀完整行的內容 |
readlines([size]) |
返回值為整個檔案內容的列表,每項是以換行符為結尾的一行字串。若指定size,表示每次讀取的位元組數 |
2、檔案的讀取
檔案的讀取有多種方法,包括: readline() readlines() read()
(1)按行讀取方式readline()
readline()每次讀取檔案中的一行,需要使用永真表示式迴圈讀取檔案。但當檔案指標移動到檔案的末尾時,依然使用readline()讀取檔案將出現錯誤。因此程式中需要新增1個判斷語句,判斷檔案指標是否移動到檔案的尾部,並且通過該語句中止迴圈。
(2)多行讀取方式
函式readlines()可一次性讀取檔案中多行資料。例如:readlines(2),可讀入兩行資料。 使用readlines()讀取檔案,需要通過迴圈訪問readlines()返回的內容。
(3)一次性讀取方式
讀取檔案最簡單的方法是使用read(),read()將從檔案中一次性讀出所有的內容,並賦值給1個字串變數。 但這種方式佔記憶體最大。 若read()帶有引數,則讀入指定位元組數。例如,read(5),讀入5個位元組的資料。
3、檔案的寫入
從計算機記憶體向檔案寫入資料。 檔案的寫入同樣有多種方法,可以使用write()、writelines()方法寫入檔案。
將字串寫入檔案開頭:
相比在檔案末尾新增字串,將字串寫入檔案開頭不那麼容易,因為作業系統沒有提供這樣的支援。 解決的方法是:將檔案讀取到一個字串中,將新文字插入到該字串,再將這個字串寫入原來的檔案。
4、檔案的刪除
刪除檔案需要使用os模組和os.path模組。
os模組提供了對系統環境、檔案、目錄等作業系統級的介面函式。
下表列出了os模組常用的檔案處理函式。
注意:os模組的open()函式與內建的open()函式的用法不同。
函式 |
描述 |
access(path,mode) |
按照mode指定的許可權訪問檔案 |
chmod(path,mode) |
改變檔案的訪問許可權 |
open*filename,flag[,mode=0o777]) |
按照mode指定的許可權開啟檔案。預設情況下,給所有使用者讀、寫、執行的許可權 |
remove(path) |
刪除path指定的檔案 |
rename(old,new) |
重新命名檔案或目錄。old表示原檔案或目錄,new表示新檔案或目錄 |
stat(path) |
返回path指定檔案的所有屬性 |
fstat(path) |
返回開啟的檔案的所有屬性 |
lseek(fd,pos,how) |
設定檔案的當前位置,返回當前位置的位元組數 |
startfile(filepath[,operation]) |
起動關聯程式開啟檔案。例如:開啟的是一個html檔案,將啟動IE瀏覽器 |
tmpfile() |
建立一個臨時檔案,檔案建立在作業系統的臨時目錄中 |
函式 |
描述 |
函式 |
描述 |
abspath(path) |
返回path所在的絕對路徑 |
isabs(s) |
測試路徑是否絕對路徑 |
dirname(p) |
返回目錄的路徑 |
isdir(path) |
判斷path指定的是否是目錄 |
exists(path) |
判斷檔案是否存在 |
isfile(path) |
判斷path指定的是否是檔案 |
getatime(filename) |
返回檔案的最後訪問時間 |
split(p) |
對路徑進行分隔,並以列表方式返回 |
getctime(filename) |
返回檔案的建立時間 |
splitext(p) |
從路徑中分割檔案的副檔名 |
getmtime(filename) |
返回檔案的最後修改時間 |
splitdrive(p) |
從路徑中分割驅動器的名稱 |
getsize(filename) |
返回檔案的大小 |
walk(top,func,arg) |
遍歷目錄數,與os.walk()功能相同 |
5、檔案的複製
file類並沒有提供直接複製檔案的方法,但可以使用read()、write()方法來實現複製檔案的功能。
複製檔案的其他方法:
shutil模組是另一個檔案、目錄的管理介面,提供了一些用於複製檔案、目錄的函式。
其中,copyfile()函式可以實現檔案的複製,move()函式可以實現檔案的移動。
copyfile(src, dst)
move(src, dst)
其中,引數src表示原始檔的路徑,dst表示目標檔案的路徑,均為字串型別。
6、檔案的重新命名
os模組的函式rename()可以對檔案或目錄進行重新命名。 在實際應用中,經常需要將某一類檔案修改為另一種型別,即修改檔案的字尾名。可以通過函式rename()和字串查詢函式來實現。
7、檔案內容的搜尋和替換
檔案內容的搜尋和替換可以使用字串查詢和替換來實現。
8、處理二進位制檔案
Python中,通常使用pickle模組處理二進位制檔案。 可以使用pickle.dump將資料結構儲存到磁碟,之後再用pickle.load從磁盤獲取資料結構。
pickle不能用於讀寫特殊格式的二進位制檔案,如各種格式的影象檔案。對這種格式的檔案,要用專用模組處理(如:PIL庫)
三、目錄的常見操作
Python的os模組和os.path模組還提供了一些針對目錄操作的函式。
1、建立目錄和刪除目錄 os模組提供的常用目錄處理函式見表
函式 |
描述 |
mkdir(path[,mode=0o777]) |
建立path指定的一個目錄 |
makedirs(name[,mode=0o777]) |
建立多級目錄,name表示為“path1\path2\…” |
rmdir(path) |
刪除path指定的目錄 |
removedirs(path) |
刪除path指定的多級目錄 |
listdir(path) |
返回path指定目錄下的所有檔名,返回值為列表 |
getcwd() |
返回當前工作目錄 |
chdir(path) |
改變當前目錄為path指定的目錄 |
walk(op,topdown=True,onerror=None) |
遍歷目錄樹 |
path.isfile(path) |
當path指定的是一個檔案的名稱時,返回True,否則返回False |
path.isdir(path) |
當path指定的是一個資料夾的名稱時,返回True,否則返回False |
stat(fname) |
返回有關fname的資訊,如大小(單位為位元組)和最後一次修改時間。詳細功能參見線上文件 |
2、目錄的遍歷
os.walk()返回的是一個三元組:tupple(dirpath, dirnames, filenames), 其中第一個為起始路徑,第二個為起始路徑下的資料夾,第三個是起始路徑下的檔案。 dirpath是一個string,代表目錄的路徑; dirnames是一個list,包含了dirpath下所有子目錄的名字; filenames是一個list,包含了非目錄檔案的名字。這些名字不包含路徑資訊,如果需要得到全路徑,需要使用 os.path.join(dirpath, name)。
3、其他目錄相關操作
返回當前目錄中的檔案和資料夾; 返回當前目錄中的指定型別檔案; 返回當前目錄中所有檔案的大小總和等。
以下為以上內容的部分示例
def make_story():
f=open('story.txt','w')
f.write('Marry had a little lamb,\n')
f.write('and then she had some more.\n')
f.close()
make_story()
#在檔案尾新增內容
def add_to_story(line,fname='story.txt'):
f=open(fname,'a')
f.write(line)
f.close()
add_to_story('haha!\n')
# 使用readline()讀檔案
f=open('story.txt')
while True:
line=f.readline()
if line:
print(line[:-1]) #去掉每行的換行符
else:
break
f.close()
print()
#多行讀取方式,使用readlines()
f=open('story.txt')
lines=f.readlines()
for line in lines:
print(line[:-1])
f.close()
print()
#使用read()讀檔案
f=open('story.txt')
context=f.read()
print(context)
f.close()
print()
#使用read()返回指定位元組的內容
f=open('story.txt')
context=f.read(5) #讀取檔案前五個位元組內容
print(context)
print(f.tell())#返回檔案物件當前指標位置
context=f.read(5)#繼續讀取5個位元組內容
print(context)
print(f.tell())#輸出檔案當前指標位置
f.close()
#使用writelines()寫檔案
f=open('hello.txt','w+')
context=['hello world!\n','hello China!\n']
f.writelines(context)
f.close()
#將字串插入到檔案開頭
def insert_tilte(title,fname='story.txt'):
f=open(fname,'r+')
temp=f.read()
temp=title+'\n'+temp
f.seek(0)
f.write(temp)
f.close()
insert_tilte('long long ago,')
f=open('companies.txt','w')
f.write('GOOGLE Inc.\n')
f.write('Microsoft Corporation\n')
f.write('Apple Inc.\n')
f.write('Facebook,Inc\n')
f.close()
f1=open('companies.txt','r')
cNames=f1.readlines()
for i in range(0,len(cNames)):
cNames[i]=str(i+1)+' '+cNames[i]
f1.close()
f2=open(r'scompanies.txt','w')
f2.writelines(cNames)
f2.close()
#檔案的刪除
import os
open('hello.txt','w')
if os.path.exists('hello.txt'):
os.remove('hello.txt')
#用read()、write() 實現檔案 複製
#建立檔案hello.txt
src=open('hello.txt','w')
context=['hello world\n','hello China\n']
src.writelines(context)
src.close()
#將hello.txt 複製到hello2.txt
src=open('hello.txt','r')
dst=open('hello2.txt','w')
dst.write(src.read())
src.close()
dst.close()
#使用shutil模組實現檔案的複製和移動
import shutil
#將hello.txt 的內容複製給hello2.txt
shutil.copyfile('hello.txt','hello2.txt')
#修改檔名
import os
ls=os.listdir('.')#返回當前目錄的檔案列表
if 'hello.txt1' in ls:
os.rename('hello1.txt','hello.txt')
# 7 從hello.txt 檔案中統計字串‘hello’出現的次數
print()
import re
f1=open('hello2.txt','r')
count=0
for s in f1.readlines():
ls=re.findall('hello',s)
if len(ls)>0:
count+=ls.count('hello')
print('查詢到'+str(count)+'個hello')
f1.close()
#將hello.txt 中字串'hello'全部替換為'hi',並將結果存為hello2.txt中
f1=open('hello.txt','r')
f2=open('hello2.txt','w')
for s in f1.readlines():
f2.write(s.replace('hello','hi'))
f1.close()
f2.close()
#二進位制檔案存取
print()
import pickle
def make_picked_file():
grades={'tom':[84,88,90,90],
'jack':[77,87,97,88],
'marry':[85,None,90,90],
'alan':[100,88,90,95]
}
outfile=open('grades.dat','wb')
pickle.dump(grades,outfile)
def get_pickle_data():
infile=open('grades.dat','rb')
grades=pickle.load(infile)
return grades
make_picked_file()
print(get_pickle_data())
#目錄的建立和刪除
import os
os.mkdir('hello6') #建立path指定的一個目錄
os.rmdir ('hello6')#刪除path 指定目錄
os.makedirs('1hello\world')
os.removedirs('1hello\world')
#用遞迴函式遍歷目錄
import os
def VisitDir(path):
ls=os.listdir(path) #返回path 指定目錄下的所有檔名和目錄名
for p in ls:
pathname=os.path.join(path,p) #連線兩個或多個路徑
if not os.path.isfile(pathname):
VisitDir(pathname)
else:
print(pathname)
if __name__=="__main__":
path=r'C:\Users\Administrator\Desktop'
VisitDir(path)
#使用os.walk
import os
def VisitDir(path):
for root,dirs,files in os.walk(path):
for filepath in files:
print(os.path.join(root,filepath))
if __name__=="__main__":
path=r'C:\Users\Administrator\Desktop'
VisitDir(path)
#返回當前目錄中的所有檔案的大小總和
import os
def list_cwd():
return os.listdir(os.getcwd()) #返回當前目錄中的所有檔名和子目錄名
def size_in_bytes(fname):
return os.stat(fname).st_size
def cwd_size_in_bytes():
total=0
for name in list_cwd():
total+=size_in_bytes(name)
return total
print(cwd_size_in_bytes())