1. 程式人生 > 實用技巧 >python學習筆記 第四章 檔案操作

python學習筆記 第四章 檔案操作

第四章 檔案操作

4.1記憶體相關

  • 示例一

    v1=[11,22,33]
    v2=[11,22,33]   #會重新開闢記憶體空間,儲存當前的值
    
    v1=666
    v2=666          #會重新開闢記憶體空間,儲存當前的值
    
    v1="abc"
    v2="abc"        #會重新開闢記憶體空間,儲存當前的值
    
  • 示例二:

    v1=[11,22,33,44]
    v1=[11,22,33]   #會重新開闢記憶體空間,儲存當前的值
    
  • 示例三:賦值操作不會開闢新的記憶體空間

    #內部修改
    v1=[1,2]
    v2=v1       #將v2的記憶體地址指向v1所指向的記憶體地址,即v1和v2指向同一個記憶體空間
    v1.append(3)   #修改V1的值, v2也會變化
    print(v2)   #[1,2,3]
    v2.append(4)  #修改v2的值,v1也會改變
    print(v1)    #[1,2,3,4]
    
    #賦值操作
    v1=[11,22,33,44]  #開闢一個新的記憶體空間,將v1重新指向他、
    #對於v2而言,其仍指向[1,2,3,4]的記憶體空間
    print(v1,v2)   #[11, 22, 33, 44] [1, 2, 3, 4]
    
    #對於字串來說,其不可進行內部修改
    v1="apple"
    v2=v1   #賦值
    v1="pear"
    print(v1,v2)  #pear,apple
    
  • 示例四:巢狀的

    v=[1,2,3]
    values=[11,22,v]
    print(values)  #[11, 22, [1, 2, 3]]
    v.append("apple")  #對v進行操作,則values因為也包含v,則其也會發生變化
    print(values)  #[11, 22, [1, 2, 3, 'apple']]
    
    values[-1].append(666)
    print(v)   #[1, 2, 3, 'apple', 666]
    
    v=9999   #values指向的還是v之前的記憶體空間
    print(values)  #[11, 22, [1, 2, 3, 'apple', 666]]
    
    values[-1]=666  #v指向的記憶體空間還是9999
    print(v)      #9999
    
    
  • 示例五

    v1=[1,2,3]
    v2=["a","b","c"]
    v3=["x","y","z",v1,v2,v1]
    
    v3[-1].append(666)  #修改了v1所指向的記憶體單元的值
    print(v1)  #[1, 2, 3, 666]
    #v3裡面也有指向v1記憶體單元的值,故v3裡面的v1值也全部會變
    print(v3)  #['x', 'y', 'z', [1, 2, 3, 666], ['a', 'b', 'c'], [1, 2, 3, 66]]
    #實際上v3裡面存的是v1和v2的記憶體地址
    
    v3[3]=999
    print(v3)  #['x', 'y', 'z', 999, ['a', 'b', 'c'], [1, 2, 3, 666]]
    print(v1)  #[1, 2, 3, 666]
    

記憶體垃圾:當此記憶體沒有指標指向它的時候,就會被系統當成垃圾

  • 檢視記憶體地址id

    v1=[1,2,3]
    v2=[1,2,3]
    
    v3=v1
    print(id(v1),id(v2),id(v3)) #1653666177608 1653666177672 1653666177608
    #v1和v3的記憶體地址是一樣的,v2的記憶體地址是新開闢的
    
    v1=999
    print(id(v1),id(v3)) #v1的記憶體地址變化了,v3的記憶體地址保持不變
    
  • python中為了記憶體優化,做了快取,提高效能,把一些相同的整型和字串會放到一個記憶體地址中

    • 整型:(-5到256)

    • 字串:除了形如"a_*" * 3

    當然只有一些整型、字串會出現這樣的情況

  • ==與is的區別

    #==是判斷數值是否相等,is是判斷記憶體地址是否相等
    
    v3=[1,2,3]
    v4=[2,3,4]
    print(v3==v4)    #False
    print(v3 is v4)  #False
    
    v1=[1,2]
    v2=[1,2]   #v1和v2的記憶體地址並不相等
    print(v1==v2)   #True
    print(v1 is v2) #False
    
    v5=[1,2,3]
    v6=v5      #v6和 v5的記憶體地址相等,則值也相等
    print(v5==v6)    #True
    print(v5 is v6)  #True
    
    #python快取機制導致的特殊情況
    v7=10
    v8=10   #由於python的快取機制,導致v7和v8實際上是一個記憶體地址
    print(v7==v8)    #True
    print(v7 is v8)  #True
    
  • 方法的記憶體操作

    print("列表的append()方法")
    v1=[1,2,3]
    v2=v1
    v1.append("apple")  #列表是可以修改的,append()不會重新開闢一個記憶體空間
    print(v1,v2)   #[1, 2, 3, 'apple'] [1, 2, 3, 'apple']
    
    print("字串的大小寫轉換如upper()")
    v3="apple"
    v4=v3
    v3.upper()    #由於是str型別,並不可變,會重新開闢一塊記憶體空間
    v5=v3.upper() # 若有接收的值,接收者能變大寫
    print(v3,v4,v5)  #apple apple APPLE
    
    print("字串型別的切片")
    v6="apple"
    v7=v6[0:2]   #字串並不可變,所以只能新開闢一塊記憶體空間接收切片的值
    print(v6,v7) #原來的值沒有修改
    
    print("集合的add()")
    v8={1,2,3}
    v9=v8
    v8.add(666)    #集合是可變型別,修改了v8地址的值,v9也會修改
    print(v8,v9)  #{1, 2, 3, 666} {1, 2, 3, 666}
    
    print("集合的intersection()")
    v10={1,2,3}
    v11=v10
    v10.intersection({1,3,5})  #需要將其結果賦值給一個新的值
    print(v10,v11)  #實際上沒有對v10和v11的元素的值修改
    
    print("列表的索引")
    v12=[1,2,3,4,5]    #列表其實存的是指向一個大 的記憶體地址
    v13=v12
    print("修改前:",id(v12[0]))  #140714809807904
    v12[0]=[6,7,8,9]   #列表中的索引指向的是一個記憶體地址,記憶體地址所指的值是索引中的值
    print("修改後:",id(v12[0]))  #1944748080712 ,修改前與後的索引地址是不同的
    #可以發現,索引指向的地址由於值發生變化,又建立一個新的記憶體空間,並重新指向該記憶體地址
    print(v12,v13)  #[[6, 7, 8, 9], 2, 3, 4, 5] [[6, 7, 8, 9], 2, 3, 4, 5]
    
    print("列表的巢狀")
    v14=[1,2]
    v15=[1,2,v14]
    v14[0]="apple"   #修改v14[0]的值,由於v15[2]指向v14的地址,所以v15[2]的值會隨著v14改變
    print(v14,v15)    #['apple', 2] [1, 2, ['apple', 2]]  v15的值也會隨著發生變化
    v15[2][1]=666    #修改的是v15所指向的v14的[1]號地址,v14和v15會隨著一起發生變化
    print(v14,v15)   #['apple', 666] [1, 2, ['apple', 666]]
    v15[2]=123        #修改的是v15[2]的值,v15[2]會重新建立一個記憶體空間,儲存記憶體地址
    print(v14,v15)    #['apple', 2] [1, 2, 123]   v14的值不會發生變化
    
    #列表/集合/字典 的記憶體 操作類似
    print("取字典key,修改values")
    v16={"k1":"v1","k2":"v2"}
    v17=v16
    print("修改前:",id(v16["k1"]))  #2358676809632
    v16["k1"]="apple"    #v17的地址指向v16,修改 v16則v17的值也會隨之改變
    print("修改後:",id(v16["k1"]))  #2358676810864
    print(v16,v17)   #{'k1': 'apple', 'k2': 'v2'} {'k1': 'apple', 'k2': 'v2'}
    
    #再來一道列表的巢狀的題
    print("列表的巢狀")
    v18=[1,2,3]
    v19=[v18,v18,v18]
    v19[0]="apple"  #只是重新開闢一塊記憶體空間,將v19[0]指向該記憶體地址
    print(v18,v19)   #[1, 2, 3] ['apple', [1, 2, 3], [1, 2, 3]]
    v18[0]=666
    print(v18,v19)   #[666, 2, 3] ['apple', [666, 2, 3], [666, 2, 3]]
    v19[2][2]=999
    print(v18,v19)  #[666, 2, 999] ['apple', [666, 2, 999], [666, 2, 999]]
    
    print("字典迴圈的記憶體相關的操作")
    v20={}
    for i  in range(10):
        v20["user"]=i
    print(v20)  #{'user': 9}
    
    print("列表中巢狀字典的迴圈")
    v21=[]
    v22={}
    for i in range(10):
        v22["user"]=i
        v21.append(v22)
    print(v21,v22)
    #[{'user': 9}, {'user': 9}, {'user': 9}, {'user': 9}, {'user': 9}, {'user': 9}, {'user': 9}, {'user': 9}, {'user': 9}, {'user': 9}] {'user': 9}
    
    v23={"k1":"v1","k1":"v2"}   #字典儲存的方法是 鍵通過雜湊演算法轉換成0101的值並儲存值的地址,根據值的地址可以找到對應的記憶體,找到真正的值
    print(v23)      #{'k1': 'v2'}  相同鍵,只會儲存最後一個鍵與值
    
    print("列表和在迴圈中建立字典並新增入列表")
    v24=[]
    for i in range(10):
        v25={}
        v25["user"]=i
        v24.append(v25)
    print(v24,v25)
    #[{'user': 0}, {'user': 1}, {'user': 2}, {'user': 3}, {'user': 4}, {'user': 5}, {'user': 6}, {'user': 7}, {'user': 8}, {'user': 9}] {'user': 9}
    
    print("列表與迴圈append()")
    v26=[1,2,3,4]
    v27=[]
    for i in v26:
        v27.append(i)   #相當於把數字的地址給到v27
    print(v26,v27)   #[1, 2, 3, 4] [1, 2, 3, 4]
    print(id(v26[0]),id(v27[0]))  #140714614182944 140714614182944  記憶體地址相同
    v27[0]=666
    print(v26,v27)   #[1, 2, 3, 4] [666, 2, 3, 4]  只修改v27的值,v26不會發生改變
    
    print("列表與迴圈append(str())")
    v28=[1,2,3,4]
    v29=[]
    for i in v28:
        v29.append(str(i))   #每次生成一個新的字串新增到v29
    print(v28,v29)   #[1, 2, 3, 4] ['1', '2', '3', '4']
    print(id(v28[0]),id(v29[0]))   #140714809807904 2747158554528 記憶體地址不相同
    
    print("帶有字串的列表與迴圈append()")
    v30=["apple","pear","cherry"]
    v31=[]
    for i in v30:
        v31.append(i.upper())
    print(v30,v31)  #['apple', 'pear', 'cherry'] ['APPLE', 'PEAR', 'CHERRY']
    print(id(v30[0]),id(v31[0]))   #2084019629952 2084019628048 記憶體地址不一樣
    
    v32=[]
    for i in v30:
        v32.append(i+"sb")    #括號中的值修改過之後就會生成新的地址,沒有修改就還是原來的地址
    print(v30,v32)    #['apple', 'pear', 'cherry'] ['applesb', 'pearsb', 'cherrysb']
    print(id(v30[0]),id(v32[0]))    #1931911098296 1931911457792  記憶體地址也不同
    
    

4.2深淺拷貝

4.2.1淺拷貝

拷貝第一層

4.2.2深拷貝

拷貝所有的資料(可變)

import  copy
#在字串、整型、布林型別、元組的拷貝中,由於這些是不可變的資料型別,深淺拷貝並沒有區別,都會開闢記憶體空間拷貝一份資料,拷貝出的資料會被copy()所賦予的值指向(究竟有沒有建立新的空間?不知道,但是由於小資料池的緣故,第一層不可變資料型別拷貝出來的記憶體地址是相同的)

v1="apple"
v2=copy.copy(v1)      #淺拷貝 由於小資料池的緣故,其記憶體地址相同(應該不一樣的)
print(id(v1),id(v2))  #2015823325256 2015823325256
v3=copy.deepcopy(v1)  #深拷貝 由於小資料池的緣故,其記憶體地址相同(應該不一樣的)
print(id(v1),id(v3))  #2015823325256 2015823325256

#淺拷貝:只拷貝第一層
#深拷貝:拷貝巢狀層次中的所有可變型別(拷貝所有的資料(可變))
v4=[1,2,3,[11,22,33]]
v5=copy.copy(v4)
v6=copy.deepcopy(v4)
print(id(v4),id(v5),id(v6))   #1895510213704 1895510273032 1895510270216
print(id(v4[0]),id(v5[0]),id(v6[0]))  #140725113574432 140725113574432 140725113574432
print(id(v4[-1]),id(v5[-1]),id(v6[-1]))  #1895510213320 1895510213320 1895510373896
#可以發現深淺拷貝的記憶體地址都是新的,這是由於深淺拷貝都會拷貝一個一樣大小的新的列表(第一層),前面三個資料是不可變型別,
#就將其記憶體地址存放到新的列表(第一層)中,也就是通過新列表(第一層)的記憶體地址可以索引到原來前面的三個資料

#但是最後一個數據是可變的列表,淺拷貝就將列表[11,22,33]的記憶體地址儲存到新的列表(第一層)中,
#深拷貝則會再建立一個新的列表(第二層)並存放11,22,33的地址,通過新列表(第二層)的地址索引到原來的資料
#同理對於字典、集合這些可變的資料型別也是如此
#注意深拷貝和淺拷貝拷貝出來的資料都是一樣的,只是地址不一樣

#特殊情況
v7=(1,2,[666.999],4)
v8=copy.copy(v7)
v9=copy.deepcopy(v7)
print(id(v7),id(v8),id(v9))   #1701626030824 1701626030824 1701626031064
#發現元組中嵌套了可變的資料型別,導致深拷貝時也會重新建立一個元組,所以元組的地址發生了變化

4.2.3修改深淺拷貝中的檔案

還是以上述程式碼的v1、v2、v3作為例子

當修改深淺拷貝的資料的時候,如需要修改v2[0]=666,為了儲存666,會重新開闢一塊記憶體空間儲存666的值,並使原來的資料地址會指向新開闢的記憶體空間的地址,這樣就保證了修改拷貝的檔案中的值不會改變到原來的v1。

4.3檔案的基本操作

obj=open("路徑",mode="模式",encoding="編碼")
obj.write(x)
y=obj.read()
obj.close()

4.4開啟模式

  • 只讀只寫字串 r / w / a
  • 可讀可寫字串 r+ / w+ / a+
  • 只讀只寫二進位制 rb / wb /ab
  • 可讀可寫二進位制 r+b / w+b / a+b

4.5讀寫操作

  • read(),全部讀到記憶體

  • read(1)

    • 1表示一個字元

      obj=open("a.txt",mode="r",encoding="utf-8")
      data=obj.read(1)  #讀取一個字元
      obj.close()
      print(data)
      
    • 1表示一個位元組

      obj=open("a.txt",mode="rb")
      data=obj.read(1)
      obj.close()
      print(data)
      
  • readlines() 逐行進行讀取

  • readline() 讀取游標後一行

  • for迴圈 可以用在超級大檔案,使得檔案不會一次性讀取到記憶體中

  • write(字串)

    obj=open("a.txt",mode="w",encoding="utf-8")
    data=obj.wirte("我要寫入檔案拉")
    obj.close()
    
  • write(二進位制)

    obj=open("a.txt",mode="wb")
    data=obj.wirte("我想用二進位制寫檔案".encode("utf-8"))
    obj.close()
    

4.6檔案的中級操作

  • 調整游標的位置seek() 以位元組為單位(無論mode是否為二進位制)

  • 獲取游標的當前所在位元組的位置tell()

    可以通過游標的操作對於大檔案的下載中斷以後繼續進行。

    obj=open("aaa.txt",mode="r",encoding="utf-8")
    data=obj.tell()
    obj.close()
    
  • flush() 強制將記憶體中的資料寫入到硬碟上

  • 詳細的關於檔案中級操作的解釋

#檔案操作
#開啟和關閉檔案  open() close()
#方式一:先開啟檔案,一頓操作以後,再關閉檔案
"""
file_obj=open("test.txt",mode="r",encoding="utf-8")
content=file_obj.read()
print(content)
file_obj.close()   #關閉的時候才會把檔案強制刷到硬碟上面
"""
#方式二:為了防止自己忘記關閉檔案,導致檔案不能從記憶體寫到硬碟上,用with...as...加縮排進行檔案操作
"""
with open("test.txt",mode="r",encoding="utf-8") as file_obj:
	data=file_obj.read()
	#縮排中的程式碼執行以後,自動關閉檔案
"""

#檔案的兩種操作:read() write()  讀和寫
#read()讀取全部的內容 / read(1) 從游標處開始往後讀取一個字元 / readlines() 逐行進行讀取,得到的是列表的形式
#readline() 僅讀取游標後一行  / for i in file_obj: 也可以逐行進行讀取,並且不會一次性放入到記憶體中,但是會有換行符,需要用strip()去除
#補充strip()可以去除空格、\n、\t等
#write()  將要寫入的內容填入括號中即可,而且可以按照write("你好胖\n")會進行換行。會根據游標的位置往後寫(需要注意有例外,如a/a+/ab)
"""
file_obj=open("aaa.txt",mode="r",encoding=("utf-8"))
content=file_obj.readlines()
print(content)     #['今朝有酒今朝醉\n', '遊湖\n', '又用\n', '與i及']
file_obj.seek(0)
content1=file_obj.readline() #直接讀取檔案的後一行
print(content1)   #今朝有酒今朝醉
print("************************")
file_obj.seek(0)   #再次把游標移動到首部
#如果需要讀取一個非常大的檔案,需要分開將檔案放入記憶體中,不至於將一個大檔案直接放入到記憶體當中
for i in file_obj:
    result=i.strip()  #在此處的主要功能就是去除\n
    print(result)   
file_obj.close()
"""


#三種基本的檔案操作mode r/w/a   的區別:
#r  是隻能讀取檔案,從游標處讀取內容,不能寫,且游標預設起始位置位於0(若沒有該檔案,則會報錯)
#w  只能寫檔案,不能讀取檔案,在檔案進行open()的時候就會先清空檔案,然後將新的檔案內容寫入,寫完以後游標會跑到最後(若沒有該檔案,則會新建一個檔案)
#a  追加寫入,不能讀,游標預設在末尾,在此mode的情況下,只能追加到末尾,無論游標移動到哪裡(若沒有該檔案,則會建立一個新的檔案)

#若是不能讀或寫的mode下面,進行讀或寫的操作會報錯:io.UnsupportedOperation: not writable
"""
file_obj=open("aaa.txt",mode="a",encoding="utf-8")
file_obj.write("你好")
file_obj.close()   #會建立一個新的檔案   
"""

#三種基本的檔案操作mode+  r+/w+/a+
#r+  可讀可寫,從游標位置開始讀寫,預設游標位置為0(檔案的開頭處)讀或者寫,寫的時候由於游標位置為0,所以會覆蓋後面的內容
"""
file_obj=open("aaa.txt",mode="r+",encoding="utf-8")
file_obj.seek(3)
content=file_obj.read()   #預設從游標的位置開始讀,當然寫也是如此
print(content)    
file_obj.close()
"""

#seek()移動游標的操作 表示把游標移動到第幾個位元組的位置,不寫預設游標在所在的mode情況
"""
file_obj=open("aaa.txt",mode="r+",encoding="utf-8")
file_obj.seek(3)  
file_obj.write("呵呵")  #如果想在末尾新增,可以先用read()就可以將游標移動到末尾,再進行寫的操作
file_obj.close()
"""

#當不知道游標處於何處時

#w+  可讀可寫,同樣進行檔案操作的時候會把檔案清空
#注意:先寫後讀,發現讀不到資料,這是由於寫完後游標已經移動到末尾,所以讀的時候仍按游標的位置開始讀就讀不到東西
"""
file_obj=open("aaa.txt",mode="w+",encoding="utf-8")  #此時檔案被清空
file_obj.write("今朝有酒今朝醉")   #寫完以後游標的位置當然是在末尾
content=file_obj.read()            #從游標開始的位置讀取,由於游標已經在末尾,讀取的東西為空
print(content+"讀不到的東西")
file_obj.seek(0)      ##所以可以先將游標移動到開始的位置,就可以讀取原來的檔案的內容
result=file_obj.read()   #在記憶體中已經 有新的內容寫入,游標從頭開始讀取,就可以得到記憶體中新寫入的內容
print(result)   #今朝有酒今朝醉
file_obj.close()
"""

#a+  可讀可寫,預設游標正在最後,所以想要讀取資料,需要將游標移動到起始位置。當然,即使游標移動到最前,也還是寫到末尾
"""
file_obj=open("aaa.txt",mode="a+",encoding="utf-8")
file_obj.write("我要寫東西")   #由於a+對於檔案寫操作都是追加到末尾,所以最終檔案的末尾會加上“我要寫東西”的字串
content=file_obj.read()    #可以讀取檔案
print(content)
file_obj.close()
"""

#注意:對於檔案操作來說,由於檔案會讀取到記憶體中,檔案一般不存在修改
#實在需要修改,其實是在記憶體中修改,再重新寫入到硬碟中,不是直接對檔案進行操作。

對於一些大的檔案來說,想要修改其中的內容,但是由於檔案過大不能一次性讀入到記憶體,可以用:

f1=open("aaa,txt",mode="r",encoding="utf-8")
f2=open("aaa.txt",mode="w",encoding="utf-8")

for line in f1:
    new_line=line.replace("帥哥","醜逼")
    f2.write(new_line)
    
f1.close()
f2.close()

#當然也可以採用with open(...) as ...: 縮排的方式直接將兩個檔案的開啟
with open("a.txt",mode="r",encoding="utf-8") as f1,open ("a",mode="w",encoding="utf-8") as f2:
    for line in f1:
        new_line=line.replace("美女","女神")
        f2.write(new_line)

4.7一些檔案操作的練習題

#一些關於檔案操作的練習題
#練習一:將user中的元素根據_連結,並寫入aaa.txt檔案中
#user=["apple","pen"]
"""
user=["apple","pear"]
data="_".join(user)       #用到字串中的連結
print(data)
file=open("aaa.txt",mode="w",encoding=("utf-8"))
file.write(data)
file.close()
"""

#練習二:將uesr中的元素根據_連結,並寫入aaa.txt的檔案中
#user=[{"name":"apple","pwd":"123"},{"name":"pen","pwd":"123"}
"""
user=[{"name":"apple","pwd":"123"},{"name":"pen","pwd":"123"}]
file=open("aaa.txt",mode="w",encoding="utf-8")
for i in user:
    #i其實是以字典的形式出現的
    result="_".join(i.values())  #也可以用key來取values 
    #line="%s%s"%(i["name"],i["pwd"])
    file.write(result+"\n")
file.close()
"""

#練習三:將aaa.txt檔案中的檔案讀取出來,並新增到一個列表user中
"""
#方式一:
user=[]
file=open("aaa.txt",mode="r",encoding="utf-8")
data=file.read()
user.append(data)
file.close()
print(user)  #['apple_123\npen_123\n']
#字串其實可以通過\n來分割一下,這裡需要 用到split() ,這個也是字串的方法
#data=data.strip()    #['apple_123', 'pen_123']
result=data.split("\n")
print(result)   #['apple_123', 'pen_123', '']這樣就可以拿到列表
#但是發現後面還有""空字串,所以可以用strip()去除

print("************華麗的分割線************")
#方式二:
user1=[]
file=open("aaa.txt",mode="r",encoding="utf-8")
for i in file:
    print(i)    #逐行進行列印,而且保留有換行符
    data1=i.strip()
    user1.append(data1)
file.close()
print(user1)  #最終也能得到['apple_123', 'pen_123']
"""

4.8理解檔案操作的本質

理解了檔案操作和進位制以後,需要理解檔案操作的本質

#理解檔案操作的本質
"""
#根據字串的內容以及encoding所指示的編碼轉化為二進位制,寫入到檔案中
file=open("aaa.txt",mode="w",encoding="utf-8")
file.write("今朝有酒今朝醉")  
file.close()
"""
"""
#讀取硬碟上的二進位制進記憶體,將二進位制按照encoding的編碼,轉換成字串
file=open("aaa.txt",mode="r",encoding="utf-8")  
data=file.read()  
file.close()
"""
#rb  直接讀取二進位制
"""
file=open("aaa.txt",mode="rb")
show=file.read()
print(show)    #b'\xe4\xbd\xa0\xe5\xa5\xbd\xe6\xa3\x92'
#可以發現讀取的是2進位制,表現出來的是16進位制(可以發現都帶\x,這代表的就是16進位制,這是為了方便表示二進位制)
file.close()   
"""

#wb  直接寫入二進位制
"""
file=open("aaa.txt",mode="wb")
#file.write("你好")   #TypeError: a bytes-like object is required, not 'str'
#報錯,顯示不能直接寫入字串,只能以二進位制的形式寫入
#所以最好先將要寫入的字元轉換成二進位制encode(),再將二進位制寫入檔案中
data="你好棒"
content=data.encode("utf-8")  #以utf-8的編碼形式,將字串轉換成二進位制
file.write(content)   #寫入二進位制
file.close()
"""

#ab  直接追加二進位制

#一般對於圖片/音訊/視訊/未知編碼,常用rb/wb/ab

字串轉二進位制 encode()

二進位制轉字串 decode()

4.9檔案的修改

with open("aaa.txt",mode="r",encoding="utf-8") as f1:
    data=f1.read()
#只能將檔案讀取到記憶體中修改
new_data=data.replace("酒","牛奶")

#將檔案從記憶體重新寫到硬碟中
with open("aaa.txt",mode="w",encoding="utf-8") as f1:
    f1.write(new_data)