1. 程式人生 > 其它 >字元編碼和檔案處理

字元編碼和檔案處理

**今日內容**:
        字元編碼

        檔案處理基本步驟

        上下文管理

        讀寫檔案的方法

        控制檔案內指標的移動
        讀寫檔案的兩種方式
**控制檔案讀寫內容的模式**

# r(預設):只讀模式
# w:只寫
# a:只寫(追加寫)
# rt wt at
# rb wb ab
# 大前提: tb模式均不能單獨使用,必須與r/w/a之一結合使用
# t(預設的):文字模式
#     1. 讀寫檔案都是以字串為單位的
#     2. 只能針對文字檔案
#     3. 必須指定encoding引數
# b:二進位制模式:
#    1.讀寫檔案都是以bytes/二進位制為單位的
#    2. 可以針對所有檔案
#    3. 一定不能指定encoding引數

**註冊與登入功能**

編寫使用者認證程式,可以完成多個賬號的登入,使用者資訊來自於檔案
建立一個db.txt檔案,存入一些賬號密碼
egon:123
qwe:456
asd:789

inp_user = input("請輸入您的賬號:").strip()
inp_pwd = input("請輸入您的密碼:").strip()
f = open('db.txt', mode='rt', encoding='utf-8')
for line in f:
    user, pwd = line.strip('\n').split(':')
    if inp_user == user and inp_pwd == pwd:
        print("登入成功")
        break
else:
    print("賬號或者密碼輸入錯誤")
f.close()
**字元編碼**

**1 什麼是字元編碼**
    人類的字元轉換成數字的過程稱之為字元編碼
    該過程需要參照一張表,該表稱之為字元編碼表

                        編碼
    人類的字元-----------轉換成--------------》數字
                        解碼
    人類的字元《-----------轉換成--------------數字

**2 字元編碼表**
    a--00    b--01   c--10    d--11
 
    ASCII: 用8bit對應一個英文字元
        可以識別英文字元

    gbk:用16bit對應一個字元
        可以識別中文字元、英文字元

    shift-JIS:
        可以識別日文字元、英文字元

    Euc-KR
        可以識別韓文字元、英文字元

    萬國字元編碼表:unicode,用16bit位對應一個字元
        兼顧兩大歷史使命
            1、可以識別萬國字元
            2、相容老的字元編碼格式

    記憶體中用的字元編碼格式預設都是unicode,而且不能改變
    我們可以改的是存入硬碟的字元編碼格式

    萬國字元------------》unicode格式的二進位制(記憶體)---------》utf-8格式的二進位制(硬碟)
    中文、英文字元------------》unicode格式的二進位制(記憶體)---------》GBK格式的二進位制(硬碟)
    日文、英文字元------------》unicode格式的二進位制(記憶體)---------》shift-JIS格式的二進位制(硬碟)

    utf-8全稱Unicode Transformation Format,

**若想保證不亂碼**
    1、保證存不亂
        存入硬碟的編碼格式要能識別輸入的字元

    2、保證讀不亂
        存取硬碟用得都是同一種字元編碼格式

    3、往硬碟存的新檔案以後都存成utf-8格式

python3 D:\全棧18期\day09\程式碼\test.py

python3直譯器預設讀檔案的編碼格式是utf-8
python2直譯器預設讀檔案的編碼格式是ASCII

**推薦用python3直譯器,因為python3直譯器存字串型別的值會儲存unicode格式
如果用到python2直譯器,記得在字串型別前加字首u**
**bytes型別**

#      編碼                   編碼
# 字元---------》unicode格式----------》utf-8格式
x = "上"

res = x.encode('utf-8')
# print(res,type(res))

#        解碼                   解碼
# 字元<---------unicode格式<----------utf-8格式
print(res.decode('utf-8')
**with上下文管理**

# f = open('db.txt',mode='rt',encoding='utf-8')
# print(f.read())
# print('='*50)
# print(f.read())
# f.close()

with open('db.txt',mode='rt',encoding='utf-8') as f:
    print(f.read())
    print('='*50)
    print(f.read())

# with open('db.txt',mode='rt',encoding='utf-8') as f,\
#         open('b.txt',mode='rt') as f1:
#     print(f.read())
#     print('='*50)
#     print(f.read())

**#** **r:如果檔案不存在則報錯,如果檔案存在則指標置於檔案開頭**
**檔案的開啟模式**

# 檔案的開啟模式分為兩大類
**# 一 控制檔案讀寫內容**
# t(預設):無論讀寫都是以字串為單位的,必須指定encoding引數
# b:無論讀寫都是以bytes為單位的

**# 二 控制檔案讀寫操作**
# r(預設):只讀模式
# w:只寫
# a:只寫(追加寫)

**# 操作檔案的流程:**
# 1. 開啟檔案,由應用程式向作業系統發起系統呼叫open(...),作業系統開啟該檔案,對應一塊硬碟空間,並返回一個檔案物件賦值給一個變數f
f=open('a.txt','r',encoding='utf-8') #預設開啟模式就為r

# 2. 呼叫檔案物件下的讀/寫方法,會被作業系統轉換為讀/寫硬碟的操作
data=f.read()

# 3. 向作業系統發起關閉檔案的請求,回收系統資源
f.close()

**# 資源回收與with上下文管理**
開啟一個檔案包含兩部分資源:應用程式的變數f和作業系統開啟的檔案。在操作完畢一個檔案時,
必須把與該檔案的這兩部分資源全部回收,回收方法為:

1、f.close() #回收作業系統開啟的檔案資源
2、del f #回收應用程式級的變數
其中del f一定要發生在f.close()之後,否則就會導致作業系統開啟的檔案無法關閉,白白佔用資源, 
而python自動的垃圾回收機制決定了我們無需考慮del f,這就要求我們,在操作完畢檔案後,一定要
記住f.close(),雖然我們如此強調,但是大多數讀者還是會不由自主地忘記f.close(),考慮到這一點,
python提供了with關鍵字來幫我們管理上下文

# 1、在執行完子程式碼塊後,with 會自動執行f.close()
with open('a.txt','w') as f:
    pass 

# 2、可用with同時開啟多個檔案,用逗號分隔開即可
with open('a.txt','r') as read_f,open('b.txt','w') as write_f:  
    data = read_f.read()
    write_f.write(data)

**指定操作文字檔案的字元編碼**
f = open(...)是由作業系統開啟檔案,如果開啟的是文字檔案,會涉及到字元編碼問題,
如果沒有為open指定編碼,那麼開啟文字檔案的預設編碼很明顯是作業系統說了算了,
作業系統會用自己的預設編碼去開啟檔案,在windows下是gbk,在linux下是utf-8。
這就用到了上節課講的字元編碼的知識:若要保證不亂碼,檔案以什麼方式存的,就要以什麼方式開啟。

f = open('a.txt','r',encoding='utf-8')

**# # r:如果不存在則報錯,如果檔案存在則指標置於檔案開頭**
# with open('a.txt',mode='rt',encoding='utf-8') as f:
#     # print(f.read())
#     # print('='*50)
#     # print(f.read())
#     # for line in f:
#     #     print(line)
#
#     f.write("你好")  # 報錯

**# # w:如果不存在則建立空文件,如果檔案存在則清空,指標置於檔案開頭**
# with open('a.txt',mode='wt',encoding='utf-8') as f:
#     # f.write("你好啊1\n")
#     # f.write("你好啊2\n")
#     # f.write("你好啊3\n")
#     print(f.read())  # 報錯

**# a:如果不存在則建立空文件,如果檔案存在則清空,指標置於檔案末尾**
# with open('c.txt',mode='at',encoding='utf-8') as f:
#     # f.write("你好啊1\n")
#     # f.write("你好啊2\n")
#     # f.write("你好啊3\n")
#
#     print(f.read())  # 報錯05 檔案的開啟模式
**檔案的操作模式**

**3.1 控制檔案讀寫操作的模式**
r(預設的):只讀
w:只寫
a:只追加寫

**3.1.1 案例一:r 模式的使用**
# r只讀模式: 在檔案不存在時則報錯,檔案存在檔案內指標直接跳到檔案開頭
 with open('a.txt',mode='r',encoding='utf-8') as f:
     res=f.read() # 會將檔案的內容由硬碟全部讀入記憶體,賦值給res

**# 小練習:實現使用者認證功能**
 inp_name=input('請輸入你的名字: ').strip()
 inp_pwd=input('請輸入你的密碼: ').strip()
 with open(r'db.txt',mode='r',encoding='utf-8') as f:
     for line in f:
         # 把使用者輸入的名字與密碼與讀出內容做比對
         u,p=line.strip('\n').split(':')
         if inp_name == u and inp_pwd == p:
             print('登入成功')
             break
     else:
         print('賬號名或者密碼錯誤')
**3.1.2 案例二:w 模式的使用**
# w只寫模式: 在檔案不存在時會建立空文件,檔案存在會清空檔案,檔案指標跑到檔案開頭
with open('b.txt',mode='w',encoding='utf-8') as f:
    f.write('你好\n')
    f.write('我好\n') 
    f.write('大家好\n')
    f.write('111\n222\n333\n')
**#強調:**
# 1 在檔案不關閉的情況下,連續的寫入,後寫的內容一定跟在前寫內容的後面
# 2 如果重新以w模式開啟檔案,則會清空檔案內容
3.1.3 案例三:a 模式的使用
# a只追加寫模式: 在檔案不存在時會建立空文件,檔案存在會將檔案指標直接移動到檔案末尾
 with open('c.txt',mode='a',encoding='utf-8') as f:
     f.write('44444\n')
     f.write('55555\n')
**#強調 w 模式與 a 模式的異同:**
# 1 相同點:在開啟的檔案不關閉的情況下,連續的寫入,新寫的內容總會跟在前寫的內容之後
# 2 不同點:以 a 模式重新開啟檔案,不會清空原檔案內容,會將檔案指標直接移動到檔案末尾,
    新寫的內容永遠寫在最後

**# 小練習:實現註冊功能:**
 name=input('username>>>: ').strip()
 pwd=input('password>>>: ').strip()
 with open('db1.txt',mode='a',encoding='utf-8') as f:
     info='%s:%s\n' %(name,pwd)
     f.write(info)
**3.1.4 案例四:+ 模式的使用(瞭解)**
# r+ w+ a+ :可讀可寫
#在平時工作中,我們只單純使用r/w/a,要麼只讀,要麼只寫,一般不用可讀可寫的模式

**3.2 控制檔案讀寫內容的模式**
大前提: tb模式均不能單獨使用,必須與r/w/a之一結合使用
t(預設的):文字模式
    1. 讀寫檔案都是以字串為單位的
    2. 只能針對文字檔案
    3. 必須指定encoding引數
b:二進位制模式:
   1.讀寫檔案都是以bytes/二進位制為單位的
   2. 可以針對所有檔案
   3. 一定不能指定encoding引數
**3.2.1 案例一:t 模式的使用**
# t 模式:如果我們指定的檔案開啟模式為r/w/a,其實預設就是rt/wt/at
 with open('a.txt',mode='rt',encoding='utf-8') as f:
     res=f.read() 
     print(type(res)) # 輸出結果為:<class 'str'>

 with open('a.txt',mode='wt',encoding='utf-8') as f:
     s='abc'
     f.write(s) # 寫入的也必須是字串型別

 #強調:t 模式只能用於操作文字檔案,無論讀寫,都應該以字串為單位,
  而存取硬碟本質都是二進位制的形式
  當指定 t 模式時,內部幫我們做了編碼與解碼
**3.2.2 案例二: b 模式的使用**
**# b: 讀寫都是以二進位制位單位**
 with open('1.mp4',mode='rb') as f:
     data=f.read()
     print(type(data)) # 輸出結果為:<class 'bytes'>

 with open('a.txt',mode='wb') as f:
     msg="你好"
     res=msg.encode('utf-8') # res為bytes型別
     f.write(res) # 在b模式下寫入檔案的只能是bytes型別

**#強調:b模式對比t模式**
1、在操作純文字檔案方面t模式幫我們省去了編碼與解碼的環節,b模式則需要手動編碼與解碼,所以此時t模式更為方便
2、針對非文字檔案(如圖片、視訊、音訊等)只能使用b模式

# 小練習: 編寫拷貝工具
src_file=input('原始檔路徑: ').strip()
dst_file=input('目標檔案路徑: ').strip()
with open(r'%s' %src_file,mode='rb') as read_f,open(r'%s' %dst_file,mode='wb') as write_f:
    for line in read_f:
        # print(line)
        write_f.write(line)

**四 操作檔案的方法**
**4.1 重點**
# 讀操作
f.read()  # 讀取所有內容,執行完該操作後,檔案指標會移動到檔案末尾
f.readline()  # 讀取一行內容,游標移動到第二行首部
f.readlines()  # 讀取每一行內容,存放於列表中

**# 強調:**
# f.read()與f.readlines()都是將內容一次性讀入內容,如果內容過大會導致記憶體溢位,若還想將內容全讀入記憶體,則必須分多次讀入,有兩種實現方式:
# 方式一
with open('a.txt',mode='rt',encoding='utf-8') as f:
    for line in f:
        print(line) # 同一時刻只讀入一行內容到記憶體中

# 方式二
with open('1.mp4',mode='rb') as f:
    while True:
        data=f.read(1024) # 同一時刻只讀入1024個Bytes到記憶體中
        if len(data) == 0:
            break
        print(data)