1. 程式人生 > >第8天文件操作

第8天文件操作

split r+ nes 所在 容易 這樣的 tin 文件的 cep

1. 文件操作

文件就是計算機的操作系統虛擬給用戶操作硬盤的一個接口。我們都知道,內存和硬盤都是存儲數據的,但是內存的數據易丟失,當我們需要在下次啟動計算機的時候還能夠看到我們寫的東西,就必須要把我們的東西寫入到硬盤中,這也就是文件存在的意義。

操作文件的三個步驟
1. 打開文件得到一個文件句柄
2. 通過這個文件句柄來對文件進行我們想要的操作
3. 向操作系統發送關閉指令,回收操作系統資源

2. 打開文件的模式

打開文件的模式總共有五種,三種純凈模式,r, w, a, 以及控制打開文件格式的兩種模式: t, b

‘‘‘
控制文件格式的兩種模式必須和三種純凈模式一塊進行使用,不能單獨使用:
三種純凈模式:
    r: 只讀,文件指針在默認在開頭,文件不存在就跑出異常
    w: 只寫,文件指針也在開頭,文件不存在就創建,存在就清空內容寫入
    a: 追加寫入,文件指針在結尾,文件不存在就創建,存在就追加寫入
控制文件格式的兩種模式:
    t:文本格式:只能操作文本文件,
在這樣的格式下一般需要指定處理文本的編碼方式,否則無法跨平臺進行使用
   b: 二進制格式: 可以操作所有的文件,因此存儲就是用的字節,所以在此模式下不能指定編碼方式 

‘‘‘

(1). r只讀模式:在文件不存在的時候報錯,文件存在指針直接跳到開頭

簡單的打開文件的方式:但是不建議這樣寫,因為如果沒有指定mode和編碼方式,采取的都是默認的,mode為rt,編碼方式為操作系統默認的編碼,如果一旦出現了跨平臺的操作,就會出現亂碼的問題!

with open(user_gbk) as f:
    print(f.readline(11))

# 無論打開什麽文件,都建議指定模式和編碼方式
with open(‘user_gbk‘, mode=‘rt‘, encoding=‘gbk‘) as f:
  print(f.read())

文件讀取的兩種模式之 【rt】模式

# 以rt模式打開的建議指定上字符編碼,單位為字符  
with open(‘user_utf-8‘, ‘rt‘, encoding=‘utf-8‘) as f:
# 把一個文件全部的內容讀取出來,返回一個字符串,一般不建議這樣讀文件,容易撐爆內存 # data = f.read() # print(data, type(data), len(data)) # 讀取當前指針所在行的值,傳遞的參數代表的是讀取幾個字符 data = f.readline(4) print(data) # 把每一行的值轉換成一個字符串,最後返回一個列表
data = f.readlines() print(data)

文件讀取的兩種模式之 【rb】模式

# 以rb模式打開的不能指定字符編碼,單位都是字節
with open(user_utf-8, rb) as f:
#     for line in f:
#         print(len(line))
    # 把一個文件全部的內容讀取出來,返回一個bytes類型,一般不建議這樣讀文件,容易撐爆內存
    # 如果我們想查看內容,就用寫入文件編碼方式解碼
    # data = f.read()
    # print(data, type(data), len(data), data.decode(‘utf-8‘))
    # 讀取當前指針所在行的值,傳遞的參數代表的是讀取幾個字節
    data = f.readline(3)
    print(data)
    # 把每一行的值轉換成bytes類型,最後返回一個列表
    data = f.readlines()
    print(data)

例題:以rb的形式讀取一張圖片

with open(ceshi.png, rb) as f:
    data = f.read()
    print(data)

(2)r只寫模式:在文件不存在的時候創建,文件存在指針直接跳到開頭,覆蓋寫入文件

文件寫入的兩種模式之 【wt】模式

# wt的模式寫入的必須是字符串
with open(user_utf-8, wt, encoding=utf-8) as f:
    f.write(中國你好!.encode(utf-8))
    line = [111, 222, 444]
    # 下面這兩種方法是一樣的
    for i in line:
        f.write(i)
    f.writelines(line)

文件寫入的兩種模式之 【wb】模式

# 寫入的是字節,因此當我們在寫入的時候創建了
# 一個字符串需要先進行編碼才能夠進行寫入
with open(user_utf-8, wb) as f:
    f.write(中國你好好!.encode(utf-8))

(3).a只寫模式:在文件不存在的時候創建,文件存在指針直接跳到文件結尾,追加寫入文件,和w的區別就是一個是清空寫入,一個是追加寫入,其他的都是一樣的。

例題:做一個簡單的拷貝文件的工具

# 拷貝文件的小工具
src_file = input(源文件路徑>>).strip()
dst_file = input(目的文件路徑>>).strip()
with open(src_file, rb) as read_f, open(dst_file, wb) as write_f:
    for line in read_f:
        write_f.write(line)

3. 文件內光標的移動

光標的移動在【rt】模式下是是字符為單位的,但是在【rb】的形式下是以字節為單位的

# rt模式 讀的是字符
with open(user_utf-8, rt, encoding=utf-8) as f:
    data = f.read(3)
    print(data)

# rb模式,讀的是字節,如果想顯示出原始的字符,得先進行解碼
with open(user_gbk, rb) as f:
    # data = f.read(3)
    # b‘\xe4\xb8\xad‘
    data = f.read(2)
    print(data, data.decode(gbk))

控制文件指針移動的方法:

f.seek(參數一, 參數二)

參數一: 指的是移動的字節數
參數二:0 模式是默認模式,在任何的打開方式下都可以使用,但是1,和2 只能在b模式下才可以進行使用
    0:文件指針以文件開頭為參照移動【參數一】個字節數,移動的字節數不能為負
    1: 文件指針以當前指針所在位置為參照移動【參數一】個字節數, 負數為左,正數為右
    2: 文件指針以文件末尾為參照移動【參數一】個字節數

f.tell()
  查看當前指針離文件頭部的字節數

0模式:

# f.seek的0模式,f.seek的指針都是以字節形式移動的
# 在我們人為操作移動的過程中,不能把一個字符給拆分開
# 否則在打印的時候會報錯
# rt模式
with open(user_utf-8, rt, encoding=utf-8) as f:
    f.read()
    f.seek(3, 0)
    print(f.tell())
    print(f.read())

# rb模式
with open(user_utf-8, rb) as f:
    f.seek(3, 0)
    print(f.tell())
    print(f.read().decode(utf-8))

1 模式

# f.seek的1模式,
# 1.只能在b模式下進行使用
# 2.偏移量可負可正,負為左,正為右
# 3.指針移動不能拆分字符,否則在解碼的時候會報錯
with open(user_utf-8, rb) as f:
    f.read()
    f.seek(-3, 1)
    print(f.read().decode(utf-8))

2 模式

# f.seek的2模式
# 1. 只能在b模式下使用
# 2. 偏移量可正可負,正返回為空,負代表指針移動
# 3.指針移動不能拆分字符,否則在解碼的時候會報錯
with open(user_utf-8, rb) as f:
    f.seek(-3, 2)
    print(f.read().decode(utf-8))

例題:tail -f access.log 模擬當前命令

command = input(請輸入命令(Q退出)>>).strip()
while True:
    try:
        if command.upper() == Q:
            break
        if command.split()[0] == tail and command.split()[1] == -f:
            # 輸入的命令沒有錯誤,獲取文件名
            file_path = command.split()[2]
            print(file_path)
            with open(file_path, rb) as f:
                # 移動指針到尾部
                f.seek(0, 2)
                while True:
                    line = f.readline()
                    # 如果沒有文件導入,就繼續循環
                    if len(line) == 0:
                        continue
                    else:
                        # 如果有文件導入就寫入文件
                        print(line.decode(utf-8))
        else:
            print(usage: tail -f file_path!)
    except:
        print(usage: tail -f file_path!)

4. 文件的修改

  文件就是計算機的操作系統給我們映射的一塊硬盤空間。對於硬盤而言,是沒有辦法修改的,我們對於硬盤的操作也只能是覆蓋寫入,因此文件也是不能修改的。但是我們會發現,我們每次打開文件的是可以對其進行的修改的,這究竟是怎麽回事呢?是因為內存。我們的數據在硬盤上是沒有辦法修改,但是在內存中確是可以進行修改的,因此我們通常所說的文件修改其實指的就是內存的修改。通過內存修改完成之後重新寫入硬盤中的。

文件修改的兩種方式:

1. 把文件全部加載到內存中,然後在內存中修改我們的數據,之後統一的寫入文件中
  優點:在文件修改過程中同一份數據只有一份
  缺點:會占用過多的內存
2. 把文件一行一行的加載到內存中,一行行的修改之後寫入到一個新的文件,當修改完成之後,刪除源文件,然後把新的文件名字改成源文件的名字。
  優點:不會占用過多的內存
  缺點:在文件修改過程中,會有兩份數據存在硬盤中。

驗證硬盤裏的數據是不能修改的:

文件內容:

你好,啊slegeg
我好
大家好
# 文件內容:
‘‘‘
你好,啊slegega
我好
大家好
‘‘‘

with open(user_utf-8, r+t, encoding=utf-8) as f:
    # 移動指針到第一行的【啊】後面
    f.seek(12, 0)
    # 寫入【中國好】三個字
    # 如果硬盤數據能夠進行修改第一行一概出現:你好,啊中國好slegega
    # 如果硬盤不能改只能覆蓋,應該出現:你好,啊中國好我好(因為把這一行後面的換行符也去掉了)
    f.write(中國好)

文件的修改方法:

文件內容:

kevin is dsb
dsb is kevin
alex is kevin 

第一種方式的把kevin全部改成SB

# 內容全部加載到內存
with open(a.txt, rt, encoding=utf-8) as f:
    res = f.read().replace(kevin, SB)

# 將修改的數據重新寫入文件中
with open(a.txt, wt, encoding=utf-8) as f:
    f.write(res)

第二種方式把所有‘SB‘全部改成kevin

# 首先打開以rt得方式打開源文件,然後以wt的形式打開一個新文件
with open(a.txt, rt, encoding=utf-8) as read_file,        open(.a.txt.swap, wt, encoding=utf-8) as write_file:
    # 修改一個值並寫入到一個新的文件中
    for line in read_file:
        res = line.replace(SB, kevin)
        write_file.write(res)
import os
os.remove(a.txt)
os.rename(.a.txt.swap, a.txt)

第8天文件操作