天天看點

python檔案處理檔案操作介紹讀取檔案寫檔案檔案操作的各種模式說明針對檔案的其他操作

檔案操作介紹

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 代表從檔案末尾開始偏移。

.................^_^