python基礎之文件讀寫


前言

文件讀寫可以說是最常用的功能之一,總結一下python內置的讀寫文件的方法。

打開文件

  • open
def open(file, mode='r', buffering=None, encoding=None, errors=None, newline=None, closefd=True):
    pass

參數說明:

  • file:文件路徑,可以是相對路徑,也可以是絕對路徑

  • mode: 文件的讀寫方式,默認‘r’,只讀方式;

  • buffering:設置緩沖策略,0用於二進制文件,1為行緩沖,用於文本模式;默認二進制文件固定大小緩沖,文本文件行緩沖

  • encoding:設置編碼,默認utf-8;該參數不能用於二進制模式;

  • errors:設置怎么處理文件的編碼異常,默認strict,發生錯誤拋出異常;設置ignore忽略編碼異常,可能導致數據丟失,這個參數不能用於二進制模式;

  • newline:設置換行符,默認換行符為'\n','\r','\r\n',寫入文件的時候,所有文本中的上述三種都會轉換成'\n'換行符;當設置為''時,也啟用默認模式;如果設置其它合法值,則使用其他值,一般不用;

  • closefd=True :設置文件描述符的狀態,當為False時,文件關閉但描述符不關閉,但是打開文件時指定了文件名,那么設置False不會起作用。

文件打開方式介紹

r:	以只讀方式打開文件。文件的指針將會放在文件的開頭。這是默認模式。
w:	打開一個文件只用於寫入。如果該文件已存在則將其覆蓋。如果該文件不存在,創建新文件。
a:	打開一個文件用於追加。如果該文件已存在,文件指針將會放在文件的結尾。也就是說,新的內容將會被寫入到已有內容之后。如果該文件不存在,創建新文件進行寫入。
x:  創建一個新文件,將其打開並編寫;如果文件已經存在報錯;
rb:	以二進制格式打開一個文件用於只讀。文件指針將會放在文件的開頭。這是默認模式。
wb:	以二進制格式打開一個文件只用於寫入。如果該文件已存在則將其覆蓋。如果該文件不存在,創建新文件。
ab:	以二進制格式打開一個文件用於追加。如果該文件已存在,文件指針將會放在文件的結尾。也就是說,新的內容將會被寫入到已有內容之后。如果該文件不存在,創建新文件進行寫入。
r+:	打開一個文件用於讀寫。文件指針將會放在文件的開頭。
w+:	打開一個文件用於讀寫。如果該文件已存在則將其覆蓋。如果該文件不存在,創建新文件。
a+:	打開一個文件用於讀寫。如果該文件已存在,文件指針將會放在文件的結尾。文件打開時會是追加模式。如果該文件不存在,創建新文件用於讀寫。
rb+:以二進制格式打開一個文件用於讀寫。文件指針將會放在文件的開頭。
wb+:以二進制格式打開一個文件用於讀寫。如果該文件已存在則將其覆蓋。如果該文件不存在,創建新文件。
ab+:以二進制格式打開一個文件用於追加。如果該文件已存在,文件指針將會放在文件的結尾。如果該文件不存在,創建新文件用於讀寫。

關閉文件

  • close()
f = open(file)
f.close()

注意:

由於文件每次打開都需要調用Close函數關閉,可以使用上下文管理器管理文件,其會自動在適當的時候關閉文件。

with open(filename) as f:
    f.read()

文件普通讀寫

方法一:read()

with open(filename) as f:
    f.read()  # 一次性讀取全部,在大文件這是不可取的
    f.read(5) # 讀取5個字節,如果使用UTF-8編碼,5表示5個漢字,也表示5個字母。
    f.read(6) # 同一個f對象,多次讀取時在上一次的基礎上繼續往下,如果超過則有多少讀多少

方法二:readline()

with open(filename) as f:
    f.readline()  # 按行來讀取,每次返回一行,
    f.readline()  # 多次讀取在上一行的基礎上往下,換行符也會被讀取

方法三:readlines()

with open(filename) as f:
    t = f.readlines()  # 按行讀取全部的內容作為一個列表返回

方法四:直接遍歷打開的文件對象,按行讀取

with open('./test.txt','r+') as f:
      for line in f:
           print(line)       

方法五:使用linecache模塊

import linecache
line = linecache.getline(filename,5)  # 讀取文件第五行的數據

說明:getline方法主要用來獲取特定的行的內容,當多次讀取文件不規則行的時候該方法能提高效率,因為其將文件的內容緩存了一份在內存中,不用每次去磁盤讀取,減少了IO,但這也意味着當讀取很大的文件的時候,內存消耗十分嚴重,因為getline內部使用了readlines方法;大文件可能造成內存溢出。

  • readable()方法可以用來判斷文件是否可讀

方法一:write()

with open(filename,'w',encoding='utf-8') as f:
    t = f.write('ddd') # 將內容寫入,必須是字符串格式,不可以是數字,返回的是字符串的個數,包括了換行符\r\n占兩個字符(windows),占一個字符\n(linux)。
    t = f.write('aaa') # 多次寫入在原來的基礎上繼續寫入

方法二:writelines()

with open(filename,'w',encoding='utf-8') as f:
    f.writelines(['aa','bb'])  # 該方法自動將列表元素拼接起來寫入文件,參數時一個可迭代對象,列表、字典、集合都可以

  • writeable()可以判斷打開的文件對象f究竟是可讀的還是可寫的。

注意的問題

  1. f.write(123):這種是不被允許的,必須轉化成二進制或字符串;

  2. open(filename,'rb',encoding='utf-8'):以二進制格式打開文件是不能指定編碼的,否則報錯

  3. 以二進制格式打開文件,寫入的必須是字節文件,同時寫入返回的是字節數;以文本模式打開,寫入的必須是文本,同時返回的是字符串個數;一個漢字字符串占3個字節。

普通字符串轉化為字節文件的方法:

  1. b'123adf':這種方法只能針對數字和字母,默認使用ascii編碼,不能轉化漢字;

  2. '123adf'.encode('utf-8):可以轉化字母和漢字;

  3. bytes('我的',encoding='utf-8'):可以轉化字母和漢字,但必須指定編碼格式;

文件的定位讀寫

  • tell():獲取文件指針的位置
with open(filename,'r',encoding='utf-8') as f:
    f.read(3)
    t = f.tell()  # 獲取指針的位置,返回3,如果讀取到換行符,換行符在windows占兩個字節
  • seek(offset,from):設置指針的位置

參數

  • offset:偏移量,設置負數表示向前偏移,正數表示向后偏移,一個漢字占3個字節,字母占一個字節
  • from:偏移的方向
0:表示文件開頭
1:表示當前位置
2:表示文件末尾
with open(filename,'r',encoding='utf-8') as f:
    f.read(3)
    a = f.seek(0,0) # 返回指針定位后的實際位置,默認偏移方向從文件開頭算起

注意

  • 在文本模式下打開文件,偏移方向只能從文件開頭算起,參數from只能為0,這是因為文本模式涉及到編碼的問題,以二進制格式打開文件就可以設置不同的方向。

  • 每次打開文件,讀操作的指針都是在文件的開頭,寫操作的指針在文件的末尾,直到文件被關閉;

幾個經典的案例

文件同時讀寫的情況

    with open('test.txt', 'r+') as f:
        print(f.tell())  # 當前指針的位置在開頭0
        a = f.read(3)  # 指針到了位置3
        print(a)
        print(f.tell())
        h = f.write('hhh')  # 從文件的末尾寫入,相當於追加數據
        print(h)
        c = f.tell()  # 指針在文件的末尾
        print(c)
        print(f.read())  # 讀取從位置3到文件原來的末尾的數據
        print(f.tell())  # 當前位置在新的文件末尾和c相同
  • 總結:r+模式下,如果同一個文件對象需要讀和寫,讀和寫各有一個指針,它們是相互獨立的,讀寫位置各不干擾;但是tell函數獲取到的位置優先表示寫的位置;即當程序執行時,如果只有讀,tell獲取的位置是讀的位置;如果出現了寫,tell獲取的位置就一定是寫的位置了,無論后面還有沒有更多的讀操作;同理其他的模式也一樣;

文件同時讀寫存在偏移的情況

with open('test.txt', 'r+') as f:
    print(f.tell())  # 當前讀指針的位置在開頭0,寫指針還未初始化
    print(f.read(3))  # 讀指針到了位置3
    print(f.tell())  # 獲取到讀指針的位置為3
    f.seek(0)  # 指針偏移到文件的開頭,只能影響一個指針
    print(f.read(3))  # 讀指針到了位置3
    h = f.write('gggg')  # 增加一個文件描述符,寫指針初始化到文件的末尾,寫入數據
    j = f.tell()  # 獲取寫的位置優先,寫指針在文件末尾
    print(j)
    f.seek(0)  # 指針偏移到文件的開頭,讀文件的數據更新,加入了寫入的數據
    j = f.tell()  # 獲取寫指針在文件的開頭
    print(j)
    h = f.write('vvvv')  # 從文件開頭寫入數據,覆蓋原來的數據
    c = f.tell()  # 獲取寫指針在文件的位置4
    print(c)
    print(f.read(4))  # 讀取從位置4往后的4個字符
    print(f.tell())  # 讀指針在文件8位置
    h = f.write('xxx')  # 從文件的末尾寫入,相當於追加數據
    print(f.tell())  # 當前位置在新的文件末尾
    print(f.read())  # 從8位置讀取所有的數據

  • 總結:
  1. seek()函數只能影響它下面的第一次的讀寫操作;並且會將上一次寫入的數據更新到讀緩沖區中;

  2. 在r+模式下,write()總是從文件的末尾寫入,除非受seek函數的影響;

  3. write()操作被偏移影響后,其后的read操作的指針會被移到write操作的位置;

文件同時讀寫存在且存在更新的情況

    with open('test.txt', 'r+') as f:
        f.read()
        f.seek(2,0)  # 定位到到文件的開頭往右2的位置
        f.truncate()  # 將2位置后所有的數據刪除
        f.write('aaa')  # 寫入新的數據
  • truncate():動態刪除數據,從當前指針刪除后面所有的數據

其他方法

  • flush():刷新文件內部緩沖,直接把內部緩沖區的數據立刻寫入文件, 而不是被動的等待輸出緩沖區寫入,一般close()函數時先調用flush(),然后再關閉文件描述符。

  • fileno:返回一個整型的文件描述符,很少用到;

  • isatty():文件是否連接到一個終端的設備;

  • truncate():文件截取,無參數時從當前的指針位置刪除后面所有;有參數時從首行首字母截取數據留下來,其余的刪除;

參考


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM