1. 程式人生 > >python 檔案處理

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())