天天看點

python基礎知識-7-記憶體、深淺、檔案操作

python其他知識目錄

 1、一些對記憶體深入了解的案例

以下列舉清單,清單/字典/集合這些可變類型都是一樣的原理

變量是個位址,指向存儲資料的記憶體空間的位址,它的實質就相當于c語言裡的指針。變量和資料都存放在記憶體裡面

1.1記憶體相關的東西 指派和修改要差別開來,指派(重新定義)是重新開辟記憶體,修改是原記憶體空間内的改變

1.2修改清單元素的底層原理圖解

v1=[1,2,3]

v2=v1

v3=v1

v2,v3指向v1指向的位址,三者指向相同的位址。對變量做修改,修改的是同一個位址的值,三者都變化

代碼驗證:

python基礎知識-7-記憶體、深淺、檔案操作
python基礎知識-7-記憶體、深淺、檔案操作
>>> v1=[1,2,3]
>>> v2=v1
>>> v3=v1
>>> id(v1)
45927400
>>> id(v2)
45927400
>>> id(v3)
45927400
>>> v3[0]="mcw"
>>> print(v2)
['mcw', 2, 3]      

View Code

python基礎知識-7-記憶體、深淺、檔案操作
python基礎知識-7-記憶體、深淺、檔案操作

 1.3指派(重新定義)清單的記憶體位址變化圖解

v2=[1]

v2重新定義,記憶體位址改變

python基礎知識-7-記憶體、深淺、檔案操作
python基礎知識-7-記憶體、深淺、檔案操作
>>> v1=[1,2,3]
>>> v2=v1
>>> v3=v1
>>> v2=[1]
>>> id(v1)
46458520
>>> id(v3)
46458520
>>> id(v2)
46519160
>>> print(v2)
[1]
>>> id(v2[0])      #資料位址一緻
504310928
>>> id(v1[0])
504310928
>>> id(v3[0])
504310928      
python基礎知識-7-記憶體、深淺、檔案操作

1.4   字元串.upper()等沒有修改原值

>>> v1="mcw"       #v1指向一個位址
>>> v2=v1          #v2指向v1指向的位址
>>> v1.upper()     #字元串無法修改,讓v1變大寫。v1.upper()後是開辟一個臨時記憶體存儲大寫的但是沒人接收,v1值沒有被修改
'MCW'
>>> print(v1,v2)
mcw mcw

      

>>> v1="mcw" #v1指向一個位址

>>> v2=v1 #v2指向v1指向的位址

>>> v3=v1.upper() #讓v1值變大寫後v3接收,但是v1值本身沒有被修改,

>>> print(v1,v2,v3)

mcw mcw MCW

1.6  清單.append(元素)等修改的是原值

v1=[1,2,3]       #v1指向一個位址

v2=v1            #v2指向v1指向的位址

v1.append(v2)     #清單可變,可修改,v1追加後v1改變,v2也改變,位址相同

print(v1,v2)

python基礎知識-7-記憶體、深淺、檔案操作
python基礎知識-7-記憶體、深淺、檔案操作
>>> v1=[1,2,3]
>>> v2=v1
>>> v1.append("mcw")
>>> print(v1,v2)
[1, 2, 3, 'mcw'] [1, 2, 3, 'mcw']
>>> id(v1)
46458880
>>> id(v2)
46458880      

1.7清單中修改不可變元素代碼以及圖解

v1=[1,2,[3,4],5]

v2[0]="mcw"

v2[2][0]="xiaoma"      #原v1[2][0]的值3,如果沒有東西指向它,那就是廢棄的垃圾,垃圾回收機制會将位址回收

python基礎知識-7-記憶體、深淺、檔案操作
python基礎知識-7-記憶體、深淺、檔案操作
>>> v1=[1,2,[3,4],5]
>>> v2=v1
>>> print(v1,v2)
[1, 2, [3, 4], 5] [1, 2, [3, 4], 5]
>>> v2[0]="mcw"
>>> print(v1,v2)
['mcw', 2, [3, 4], 5] ['mcw', 2, [3, 4], 5]
>>> id(v2[2][0])
504310960
>>> id(v2[2][1])
504310976
>>> id(v2[2])
46458800
>>> v2[2][0]="xiaoma"
>>> id(v2[2][0])               #v2[2][0]位址改變
46485536
>>> id(v2[2][1])              #v2[2][1]位址沒變
504310976
>>> id(v2[2])                    #外層清單v2[2]位址沒發生改變,但是v2[2][0]的指向了另外一個新位址
46458800
>>> print(v1,v2)
['mcw', 2, ['xiaoma', 4], 5] ['mcw', 2, ['xiaoma', 4], 5]      
python基礎知識-7-記憶體、深淺、檔案操作

1.8清單中修改可變元素代碼以及圖解

v2[2]=[2,4,6]

>>> v1=[1,2,[3,4],5]
>>> v2=v1
>>> id(v1[2])      #[3,4]
46458880
>>> id(v1[1])      # 2
504310944
>>> id(v1[2][1])   #4
504310976
>>> 
>>> v2[2]=[2,4,6]
>>> id(v1[2])         #[1,4,6]
46563856
>>> id(v1[2][0])     #2
504310944
>>> id(v1[2][1])      #4
504310976      
python基礎知識-7-記憶體、深淺、檔案操作
python基礎知識-7-記憶體、深淺、檔案操作

2、深拷貝,淺拷貝

可結合上面一些對記憶體深入了解的案例進行學習

2.1#str+int+bool拷貝都是這樣:

a="mcw"

b=copy.copy(a) #淺拷貝

python基礎知識-7-記憶體、深淺、檔案操作
python基礎知識-7-記憶體、深淺、檔案操作
>>> import copy
>>> a="mcw"
>>> b=copy.copy(a)
>>> c=copy.copy(a)
>>> id(a) is id(b)
False
>>> bool(a==b)
True
>>> id(a[0]) is id(b[0])
False      

c=copt.deepcopy(a) #深拷貝

python基礎知識-7-記憶體、深淺、檔案操作
python基礎知識-7-記憶體、深淺、檔案操作
>>> import copy
>>> a="mcw"
>>> c=copy.deepcopy(a)
>>> id(a) is id(c)
False
>>> bool(a==c)
True
>>> id(a[0]) is id(c[0])
False      

2.2、#list+set+dict的深淺拷貝

 沒有嵌套的時候:

淺拷貝:拷貝記憶體位址,即變量名字 隻拷貝空殼

深拷貝:找到所有的可變類型資料(資料存放的記憶體空間)拷貝一份,不可變資料類型不拷貝,得到的結果一樣   

有嵌套的時候:

淺拷貝:拷貝記憶體位址,即變量名字,拷貝空殼

深拷貝:找到所有的可變類型資料(資料存放的記憶體空間)拷貝一份,不可變資料類型不拷貝,得到的結果一樣。嵌套的把變化的拷貝,某層不變的就不拷貝   

 --------

應該每次都拷貝一份(但由于小資料池)

---------------------

帶疑問的總結:

淺拷貝:

隻拷貝第一層(疑問:拷貝清單,新的清單位址是不同的,但是新的清單裡清單元素無論是否

可變,都是指向原有元素的位址?隻拷貝第一層的位址指向 思考,那麼隻要是淺拷貝的值和位址都是

一樣的嗎,無論清單元素是否可變)(遇到元素無論是否可變都是拷貝的相同的指針)

深拷貝:

拷貝嵌套層次中的所有可變類型(疑問:拷貝清單,新的清單位址變了,内部不變的元素位址

指向原清單元素位址,但是可變的元素會再開辟新的記憶體位址(新的記憶體位址中的子元素如果不可變那

麼指向上層的元素的位址,新的記憶體位址中的子元素如果可變再開辟新的位址,将它本身放在新的位址

,但是子元素的子元素需要再次做判斷 #再次開辟的記憶體中不變的元素位址和原來還是相同?))(1

、遇到元素不可變的拷貝元素的指針,2、遇到不可變的就生成新的位址。3假如不可變的裡面還有元素

,對于這裡的元素繼續循環執行第一步和第二部的操作)

2.3深淺拷貝特殊情況:

元組裡面元素都是不可變的情況:

v1=(1,2,3,4)

淺:沒有換位址

深:沒有換位址

由于不可變類型,是以拷貝的時候不改變位址

元組裡面元素有可變的情況:

元組裡面有可變的,會把元組拷貝一下,元組改變了

v1=(1,2,[1,2,3],4)

淺:沒變

深:變了

3、檔案操作:

 3.1檔案操作簡單介紹:

參考:http://www.runoob.com/python3/python3-file-methods.html

open() 方法

Python open() 方法用于打開一個檔案,并傳回檔案對象,在對檔案進行處理過程都需要使用到這個函數,如果該檔案無法被打開,會抛出 OSError。

注意:使用 open() 方法一定要保證關閉檔案對象,即調用 close() 方法。

open() 函數常用形式是接收兩個參數:檔案名(file)和模式(mode)。

open(file, mode='r')      

完整的文法格式為:

open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
#建立空檔案,open使用w,a,w+,a+的方式可以建立。r,r+的方式不可以建立空檔案      

參數說明:

  • file: 必需,檔案路徑(相對或者絕對路徑)。
  • mode: 可選,檔案打開模式
  • buffering: 設定緩沖
  • encoding: 一般使用utf8
  • errors: 報錯級别
  • newline: 區分換行符
  • closefd: 傳入的file參數類型
  • opener:

mode 參數有:

模式 描述
t 文本模式 (預設)。
x 寫模式,建立一個檔案,如果該檔案已存在則會報錯。
b 二進制模式。
+ 打開一個檔案進行更新(可讀可寫)。
U 通用換行模式(不推薦)。
r 以隻讀方式打開檔案。檔案的指針将會放在檔案的開頭。這是預設模式。
rb 以二進制格式打開一個檔案用于隻讀。檔案指針将會放在檔案的開頭。這是預設模式。一般用于非文本檔案如圖檔等。
r+ 打開一個檔案用于讀寫。檔案指針将會放在檔案的開頭。
rb+ 以二進制格式打開一個檔案用于讀寫。檔案指針将會放在檔案的開頭。一般用于非文本檔案如圖檔等。
w 打開一個檔案隻用于寫入。如果該檔案已存在則打開檔案,并從開頭開始編輯,即原有内容會被删除。如果該檔案不存在,建立新檔案。
wb 以二進制格式打開一個檔案隻用于寫入。如果該檔案已存在則打開檔案,并從開頭開始編輯,即原有内容會被删除。如果該檔案不存在,建立新檔案。一般用于非文本檔案如圖檔等。
w+ 打開一個檔案用于讀寫。如果該檔案已存在則打開檔案,并從開頭開始編輯,即原有内容會被删除。如果該檔案不存在,建立新檔案。
wb+ 以二進制格式打開一個檔案用于讀寫。如果該檔案已存在則打開檔案,并從開頭開始編輯,即原有内容會被删除。如果該檔案不存在,建立新檔案。一般用于非文本檔案如圖檔等。
a 打開一個檔案用于追加。如果該檔案已存在,檔案指針将會放在檔案的結尾。也就是說,新的内容将會被寫入到已有内容之後。如果該檔案不存在,建立新檔案進行寫入。
ab 以二進制格式打開一個檔案用于追加。如果該檔案已存在,檔案指針将會放在檔案的結尾。也就是說,新的内容将會被寫入到已有内容之後。如果該檔案不存在,建立新檔案進行寫入。
a+ 打開一個檔案用于讀寫。如果該檔案已存在,檔案指針将會放在檔案的結尾。檔案打開時會是追加模式。如果該檔案不存在,建立新檔案用于讀寫。
ab+ 以二進制格式打開一個檔案用于追加。如果該檔案已存在,檔案指針将會放在檔案的結尾。如果該檔案不存在,建立新檔案用于讀寫。

預設為文本模式,如果要以二進制模式打開,加上 b 。

3.2、隻讀:r 隻讀不能寫 檔案不存在報錯

utf-8的檔案,

# 打開檔案

file_object = open('log.txt',mode='r',encoding='utf-8') # 打開方式權限mode有r,read;

w,write; a,append; encoding

讀取内容:

變量=打開的檔案.read()

content = file_object.read()

print(content)

# 關閉檔案

file_object.close()

???open() 加載到記憶體,write 寫入資料到記憶體中,close将記憶體資料寫入磁盤????

使用範例:
1)
file_object = open('mcw.txt',mode='r',encoding='utf-8')
content = file_object.read()
print(content)
file_object.close()
---------------結果:
FileNotFoundError: [Errno 2] No such file or directory: 'mcw.txt'
問題原因:沒有這個檔案
解決辦法:在腳本的同一個目錄下建立檔案mcw.txt,并寫入内容:小馬過河測試。然後執行代碼
2)
file_object = open('mcw.txt',mode='r',encoding='utf-8')
content = file_object.read()
print(content)
file_object.close()
----------------結果:
 (result, consumed) = self._buffer_decode(data, self.errors, final)
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xc2 in position 2: invalid 

continuation byte
問題原因:Windows下手動建立的mcw.txt文本編碼格式為ANSI,
解決辦法:打開mcw.txt另存為utf-8格式的mcw.txt檔案
3)
file_object = open('mcw.txt',mode='r',encoding='utf-8')
content = file_object.read()
print(content)
file_object.close()
------------------結果:
小馬過河測試


機器内部似乎有個utf-8 unicode的轉換,疑問      

3.3、隻寫:w 隻寫權限不能讀。檔案不存在則建立

file_object = open('log.txt',mode='w',encoding='utf-8') # r,read; w,write; a,append;#隻寫

打開的話,會先清空,再寫,需要小心。一般用于建立檔案

# 寫内容

變量=打開的檔案.write("")

# file_object.write('mcw')

打開的檔案.close()

使用範例:
1)
file_object = open('mcw.txt',mode='r',encoding='utf-8')
file_object.write('mcw')
file_object.close()
--------------結果:
  file_object = open('mcw.txt',mode='r',encoding='utf-8')
FileNotFoundError: [Errno 2] No such file or directory: 'mcw.txt'
問題原因:沒有這個檔案
解決辦法:在腳本的同一個目錄下建立空檔案mcw.txt(utf-8格式的),然後執行代碼
2)
file_object = open('mcw.txt',mode='r',encoding='utf-8')
file_object.write('我是魔降風雲變')
file_object.close()
----------------結果:
    file_object.write('我是魔降風雲變')
io.UnsupportedOperation: not writable
問題原因:我的mode是"r",不是"w"模式,
解決辦法:修改open的參數mode為需要的可寫模式
3)
file_object = open('mcw.txt',mode='w',encoding='utf-8')
file_object.write('我是魔降風雲變')
file_object.close()
-------------結果:
沒有輸出,沒有檔案。執行代碼後,在腳本目前目錄下建立檔案mcw.txt,并寫入“我是魔降風雲變”
4)
file_object = open('mcw.txt',mode='w',encoding='utf-8')
file_object.write('我是魔降風雲變')
file_object.close()
--------------結果:
沒有輸出,打開原本為空的mcw.txt文本,裡面出現内容我是魔降風雲變

        
python基礎知識-7-記憶體、深淺、檔案操作
5)
file_object = open('mcw.txt',mode='w',encoding='utf-8')
file_object.write('我是小馬過河')
file_object.close()
---------------結果:
沒有輸出,mcw.txt文本裡面的“我是魔降風雲變”原内容被新寫的“我是小馬過河”覆寫掉

        
python基礎知識-7-記憶體、深淺、檔案操作
6)
file_object = open('mcw.txt',mode='w',encoding='gbk')
file_object.write('我是mcw')
file_object.close()
-------------結果:
将上面的代碼改為encoding="gbk",在Windows上還是能覆寫掉原來的内容,打開也能正常的看,沒亂碼

顯示.
7、沒有讀的權限      
file_object = open('mcw.txt',mode='w',encoding='utf-8')
file_object.read()
file_object.close()
--------------------------結果:      

file_object.read()

io.UnsupportedOperation: not readable

 8)
      
file_object = open('mcw.txt',mode='w',encoding='utf-8')
file_object.close()
--------------結果:
建立一個空檔案mcw.txt      

3.4、 隻追加:a 不能讀 檔案不存在則建立

open("檔案路徑",mode="a",encoding="utf-8")

追加,在檔案後面添加内容

file_object = open('logfffff.txt',mode='a',encoding='utf-8') # r,read(隻讀); w,write(隻寫,

先清空,一般用于建立檔案); a,append;

file_object.write('你好')

使用範例:
1)
file_object = open('mcw.txt',mode='a',encoding='utf-8')
file_object.write('我喜歡吃米飯')
file_object.close()
---------------結果:
沒有列印輸出,沒有mcw.txt檔案。執行代碼後,自動在腳本目前目錄建立檔案mcw.txt,并寫入内容:

“我喜歡吃米飯”

        
python基礎知識-7-記憶體、深淺、檔案操作
2)
file_object = open('mcw.txt',mode='a',encoding='utf-8')
file_object.write(' 我叫小馬過河')
file_object.close()
---------------結果:
已有檔案mcw.txt,檔案内容為“我喜歡吃米飯”.執行代碼後,檔案内容為“我喜歡吃米飯 我叫小馬過

河”,追加了“ 我叫小馬過河”

        
python基礎知識-7-記憶體、深淺、檔案操作
3)a沒有可讀權限
file_object = open('mcw.txt',mode='a',encoding='utf-8')
file_object.write('我喜歡吃米飯')
file_object.read()
file_object.close()
-------------------結果:
file_object.read()
io.UnsupportedOperation: not readable          

綜上:讀,檔案不存在會報錯,寫、追加檔案不存在都建立

3.4、可讀可寫:  r+

讀:預設從0的光标開始讀,也可以通過seek調整光标的位置

寫:根據光标的位置,從目前光标位置開始進行寫入操作(可能會将其他的文字覆寫)

open("檔案路徑",mode="r+",encoding="utf-8")

先讀後寫,先寫後讀,讀前後有寫各是什麼情況呢

有一個标記,預設在最左邊。如果有值,往裡寫一個字元,覆寫标記後一個字元。

打開的檔案.seek(位元組),移動标記的。

先讀,讀完後光标會移到最後,然後再寫,不會影響文本已有的内容,相當于追加了

file_object = open('log.txt',mode='r+',encoding='utf-8')

1)# file_object.seek(2) # 調整光标的位置

file_object.write('浪')

# # 讀取内容

# content = file_object.read()

# print(content)

#

# file_object.write('666')

使用範例:
環境為:存在mcw.txt文檔,裡面内容為“我喜歡吃米飯 我叫小馬過河”,開頭沒有空格
1)
file_object = open('mcw.txt',mode='r+',encoding='utf-8')
file_object.seek()
content = file_object.read()
print(content)
--------------結果:
    file_object.seek()
TypeError: seek() takes at least 1 argument (0 given)
問題原因:seek裡面要接參數,可以接參數“位元組”
2)
file_object = open('mcw.txt',mode='r+',encoding='utf-8')
file_object.seek(0)
content = file_object.read()
print(content)
----------------結果:
?我喜歡吃米飯 我叫小馬過河
備注:似乎seek接0的時候從開頭列印,列印出來的開頭貌似有點空格;
    seek接3的時候從文本第一個字開始列印,    
    seek接6的時候,從“喜”開始往後列印
    utf-8是三個位元組一個漢字
3)
file_object = open('mcw.txt',mode='r+',encoding='utf-8')
file_object.seek(0)
file_object.write('mcw')
content = file_object.read()
print(content)
file_object.close()
---------------結果:
原文檔mcw.txt的内容為“我喜歡吃米飯 我叫小馬過河”,列印輸出内容為“我喜歡吃米飯 我叫小馬過

河”,打開檔案檢視mcw.txt檔案内容為“mcw我喜歡吃米飯 我叫小馬過河”,開頭增加了寫入的内容“

mcw”。第二次隻列印内容不寫入,就會顯示出“mcw我喜歡吃米飯 我叫小馬過河”

        
python基礎知識-7-記憶體、深淺、檔案操作
4)
file_object = open('mcw.txt',mode='r+',encoding='utf-8')
file_object.seek(0)
content = file_object.read()
file_object.write('666')
print(content)
file_object.close()
----------------結果:
原文檔mcw.txt的内容為“mcw我喜歡吃米飯 我叫小馬過河”,列印輸出内容為“mcw我喜歡吃米飯 我叫

小馬過河”。打開檔案檢視在檔案結尾加了内容“mcw我喜歡吃米飯 我叫小馬過河666”
5)
file_object = open('mcw.txt',mode='r+',encoding='utf-8')
file_object.write('666')
content = file_object.read()
print(content)
file_object.close()
--------------結果:
這次沒有設定光标,原文檔内容“我喜歡吃米飯 我叫小馬過河”,寫入“666”後檢視檔案内容“666我

喜歡吃米飯 我叫小馬過河”
這次沒有設定光标,原文檔内容“我喜歡吃米飯 我叫小馬過河”,寫入“小馬”後檢視檔案内容“小馬

喜歡吃米飯 我叫小馬過河”
這次沒有設定光标,并且在上次操作後不是重新修改儲存的文檔,原文檔内容“小馬喜歡吃米飯 我叫小

馬過河”,寫入“,”後檢視檔案内容“,馬喜歡吃米飯 我叫小馬過河”
這次沒有設定光标,并且在上次操作後不是重新修改儲存的文檔,原文檔内容“,馬喜歡吃米飯 我叫小

馬過河”,寫入“ccccc”後檢視檔案内容“ccccc枩娆㈠悆绫抽キ 鎴戝彨灏忛┈杩囨渤”,亂碼了
這次沒有設定光标,原文檔内容“我喜歡吃米飯 我叫小馬過河”,寫入“ cc”後(cc前有個空格)檢視

檔案内容“ cc我喜歡吃米飯 我叫小馬過河”,沒有亂碼
6)
file_object = open('mcw.txt',mode='r+',encoding='utf-8')
file_object.seek(0)
file_object.write('小')
content = file_object.read()
print(content)
file_object.close()
---------------結果:
原檔案内容“我喜歡吃米飯 我叫小馬過河”,seek(0),寫入“小”後,檔案内容變為“小我喜歡吃米

飯 我叫小馬過河” pycharm列印輸出“我喜歡吃米飯 我叫小馬過河”
原檔案内容“我喜歡吃米飯 我叫小馬過河”,seek(0),寫入“小麗”後,檔案内容變為“小麗喜歡吃

米飯 我叫小馬過河” pycharm列印輸出“喜歡吃米飯 我叫小馬過河”
原檔案内容“我喜歡吃米飯 我叫小馬過河”,seek(0),寫入“你喜歡吃面條 你叫楊舟舟”後,檔案

内容變為“你喜歡吃面條 你叫楊舟舟過河”,pycharm列印輸出“過河”
原檔案内容“我喜歡吃米飯 我叫小馬過河”,seek(2),寫入“小小”後,檔案内容變為“锘灏忓皬滄

鍚冪背楗?鎴戝彨灏忛┈杩囨渤”,pycharm列印輸出“UnicodeDecodeError: 'utf-8' codec can't 

decode byte 0x9c in position 0: invalid start byte”由于seek的位元組數不是3的倍數,也就是不是

一個utf-8漢字 3個位元組的倍數報錯。我是重新把檔案轉為utf-8操作才能重新用這個檔案的
原檔案内容“我喜歡吃米飯 我叫小馬過河”,seek(0),寫入“mm”後,檔案内容變為“mm挎垜鍠滄

鍚冪背楗?鎴戝彨灏忛┈杩囨渤”,pycharm列印輸出“UnicodeDecodeError: 'utf-8' codec can't 

decode byte 0x9c in position 0: invalid start byte”由于寫入的位元組數不是3的倍數,也就是不是

一個utf-8漢字 3個位元組的倍數報錯。我是重新把檔案轉為utf-8操作才能重新用這個檔案的
原檔案内容“ cc我喜999吃米飯 我叫小馬過河”,seek(6),寫入“666”後,檔案内容變為“ cc我

666999吃米飯 我叫小馬過河”,覆寫了第6個位元組之後的三個位元組。 pycharm列印輸出“999吃米飯 我

叫小馬過河”      

綜上:seek(位元組數)或寫入的位元組數不是3的倍數就會出現亂碼。Windows上和pycharm上操作,txt文本

前面有三個位元組的空内容,可以寫入内容,如果寫入的大于3個位元組的内容,就會開始覆寫第一個中文字

符。如果是代碼操作後沒有手動粘貼儲存文檔的話,重新對檔案操作,開頭沒有那3個位元組了。如果寫入

的不夠3的倍數,加空格補充到3的倍數不會亂碼。seek(位元組數),再寫入,會從位元組數之後開始覆寫。

不用seek,預設從頭開始覆寫.

 3.5、w+寫讀: w+ 不同于讀寫

讀:預設光标永遠在寫入的最後或0,也可以通過 seek 調整光标的位置。

寫:寫入時會将檔案清空,讀取時需要調整光标到想讀的位置(光标預設在最後,到開頭seek(0))

open("檔案路徑",mode="w+",encoding="utf-8")

file_object = open('mcw.txt',mode='w+',encoding='utf-8')

data = file_object.read()

print(data)

file_object.write('小馬過河')

file_object.seek(0)

實驗案例:
1)
file_object = open('mcw.txt',mode='w+',encoding='utf-8')
data = file_object.read()
print(data)
------------------結果:
mcw.txt中有内容,執行代碼之後情況,沒有讀出内容,即使在讀之前添加seek也不行。執行寫入時會将檔案清空
2)
file_object = open('mcw.txt',mode='w+',encoding='utf-8')
file_object.write("魔降風雲變")
data = file_object.read()
print(data)
------------------結果:
mcw.txt中有内容“小馬過河”,多次執行代碼都是寫入了“魔降風雲變”,并将之前的已有的内容清空了。pycharm沒有列印出内容。

        
python基礎知識-7-記憶體、深淺、檔案操作
3)
file_object = open('mcw.txt',mode='w+',encoding='utf-8')
file_object.write("小馬過河")
file_object.seek(6)
data = file_object.read()
print(data)
file_object.close()
----------------------結果:
mcw.txt中有内容“魔降風雲變”,多次執行代碼都是寫入了“小馬過河”,寫完後seek(6),讀取到第6個位元組之後的内容“過河”并在pycharm列印出來。,每次執行都将之前已有的内容清空了。      

 3.6、a+

  • 讀:預設光标在最後,也可以通過 seek 調整光标的位置。然後再去讀取。
  • 寫:永遠寫到最後。

 pen("檔案路徑",mode="a+",encoding="utf-8")

光标預設放在最後。想讀先要移動光标到開頭)(seek(0))。a+  不存在修改,不會在光标處往後覆寫.隻要一寫,無論光标在哪裡都會立即跳到

最後然後進行追加内容。

檔案打開方式

file_object = open('mcw.txt',mode='a+',encoding='utf-8')

# file_object.seek(0)

# data = file_object.read()

# print(data)

file_object.write('666')

實驗案例:
1)
file_object = open('mcw.txt',mode='a+',encoding='utf-8')
file_object.write("小馬過河")
file_object.close()
-------------結果:
mcw.txt檔案不存在就會建立,并寫入内容“小馬過河”
2)
file_object = open('mcw.txt',mode='a+',encoding='utf-8')
file_object.seek(0)
data = file_object.read()
print(data)
-----------------結果:
如果沒有file_object.seek(0),光标預設在最後,沒有讀出内容。設定光标在開頭才讀出了内容,注意:讀内容需要有變量去接收内容并将它列印,才能顯示出來
3)
file_object = open('mcw.txt',mode='a+',encoding='utf-8')
file_object.write("下午,你好呀!")
file_object.seek(0)
data=file_object.read()
print(data)
-----------------結果:
原檔案内容為“小馬過河”,執行後,檔案後面追加了“下午,你好呀”,檔案内容變為“小馬過河下午,你好呀!”,pycharm列印輸出“小馬過河下午,你好呀!”

        
python基礎知識-7-記憶體、深淺、檔案操作
4)
file_object = open('mcw.txt',mode='a+',encoding='utf-8')
file_object.seek(0)
file_object.write("我很好")
file_object.close()
--------------結果:
後面追加内容了。即使光标移到最前面,隻要一寫,無論光标在哪裡都會立即跳到最後然後進行追加内容。試驗表明,追加之後光标在最後需要重新seek調整,不然讀不到内容。

        
python基礎知識-7-記憶體、深淺、檔案操作

小點: r**  w**  a*  r+ w+ a+  使用頻率

讀取檔案内容到記憶體,在記憶體中修改,點選儲存才會重新将修改的内容寫入磁盤  打開的檔案.read(字元個數,預設為所有似乎)

3.7、檔案讀操作:

檔案讀操作:

設定光标位置,往後讀取幾個字元

file_object = open('mcw.txt',mode='r',encoding='utf-8')

python基礎知識-7-記憶體、深淺、檔案操作

1)讀取檔案的所有内容到記憶體。

如果檔案大于記憶體,那麼記憶體裝不下全部内容。是以如果以後讀取一個特别大的檔案,那就一點一點的

file_object = open('mcw.txt',mode='r',encoding='utf-8')
data = file_object.read()
print(data)
file_object.close()
--------------結果:
read要有變量接收并列印

        
python基礎知識-7-記憶體、深淺、檔案操作

2)# 讀取檔案的所有内容到記憶體,并按照每一行進行分割到清單中。#可對每行去掉\n,在做操作

# data_list = file_object.readlines()

# print(data_list)

file_object = open('mcw.txt',mode='r',encoding='utf-8')
data_list = file_object.readlines()
print(data_list)
file_object.close()
---------------結果:
['\ufeff我叫小馬過河\n', '我來自虛空深處。\n', '我來了,可是地球人說,魔降風雲變。']

      
with open("mcw.txt",mode="r",encoding="utf-8") as f:
    content = f.read()
    row_list=content.split("\n")        #将檔案都讀出來,然後去掉每行的換行符形成的清單
    print(row_list)
--------------------結果:
['\ufeff我叫小馬過河', '明天,你好']      

3)指定單詞讀取檔案的字元個數,連續讀取出來

start=0

whle True:用

date=對象.read(字元個數) #很少

file_object = open('mcw.txt',mode='r',encoding='utf-8')
while True:
    data=file_object.read(2)
    print(data)
-----------結果:
檔案内容死循環從裡面每次列印兩個字元的大小。檔案内容循環結束,列印空的内容      

4)# 指定讀取目前光标所在的位置後的字元個數

# data = file_object.read(4)

file_object = open('mcw.txt',mode='r',encoding='utf-8')
data = file_object.read(4)
print(data)
file_object.close()
----------結果:
”列印出“我叫小”,由于開頭有一個特殊字元,是以顯示少了一個      

5)# 如果以後讀取一個特别大的檔案 (用的最多)

如果有換行符号\n,也可以用strip去符号

方法一:

for 變量line in 打開的檔案:

line=line.strip()

# for line in file_object:

# line = line.strip()

# print(line)

# file_object.close()

file_object = open('mcw.txt',mode='r',encoding='utf-8')
for line in file_object:
    line=line.strip()
    print(line)
file_object.close()
----------------結果:
我叫小馬過河
我來自虛空深處。
我來了,可是地球人說,魔降風雲變。      

或者:

file_object = open('mcw.txt',mode='r',encoding='utf-8')
data_list = file_object.readlines()
print(data_list)
file_object.close()
-----------結果:
['\ufeff我叫小馬過河\n', '我來自虛空深處。\n', '我來了,可是地球人說,魔降風雲變。']

strip去掉\n的換行符
li=[]
file_object = open('mcw.txt',mode='r',encoding='utf-8')
data_list = file_object.readlines()
for i in data_list:
    li.append(i.strip())
print(li)
file_object.close()
-------------------結果:
['\ufeff我叫小馬過河', '我來自虛空深處。', '我來了,可是地球人說,魔降風雲變。']      

3.8、檔案寫操作:

open("檔案路徑",mode="w",encoding="utf-8")

寫,往後寫,換行\n。寫完要關閉,寫的在記憶體,當關閉的時候強制刷到硬碟裡面

file_object = open('mcw.txt',mode='w',encoding='utf-8')

file_object.write('asdfadsfasdf\n')

file_object.write('asdfasdfasdfsadf')

file_object = open('mcw.txt',mode='w',encoding='utf-8')
file_object.write('abc\ndef')
file_object.close()
-----------結果:
覆寫了之前的内容。\n換行符生效,起到換行作用      

 3.9将多個windows目錄下的檔案内容統一寫到一個檔案,并增加檔案名字分隔開來

import os
from datetime import datetime
basedir="D:\BaiduNetdiskDownload\XXX從入門到精通PPT\課本源代碼"
bb=os.walk(basedir)
for a,b,c in bb:
    for i in c:
        filep=os.path.join(a,i)
        li=[]
        with open(filep,mode="rb") as f:
            for line in f:
                li.append(line)
        with open('mcw.txt', mode="ab") as f:

            # f.write(("\n----------------------------開始-%s------------------------------\n"%i).encode("gbk"))
            f.write('\r\n'.encode())
            f.write('\r\n'.encode())
            f.write('\r\n'.encode())
            f.write(("-------開始-%s----收集by小馬過河-----"%i).encode("gbk"))
            f.write('\r\n'.encode())
            f.write('\r\n'.encode())
            # f.write(('\n--------------------------------------------------------------\n').encode("gbk"))
            for j in li:
                f.write(j)
            f.write('\r\n'.encode())
            f.write(("-------結束-%s----收集by魔降風雲變-----"%i).encode("gbk"))
            f.write(datetime.now().strftime("%Y_%m_%d %H:%M:%S").encode('gbk'))
            f.write('\r\n'.encode())
        print(filep)      

注意點:

  1)rb讀取,ab追加。Windows裡追加用gbk不會亂碼。

  2)這裡加入\n不換行,加入\r\n才換行    

 3.10、使用seek定位行内容的案例

# 1.有一個檔案,這個檔案中有20000行資料,開啟一個線程池,為每100行建立一個任務,列印這100行資料。
# import time
# from threading import Thread
# from concurrent.futures import ThreadPoolExecutor
#
# # with open('mcw.txt',mode="a",encoding="utf-8") as f :
# #     for i in range(0,20000):
# #         f.write("魔降風雲變-%s\n"%i)
# shang=int(20000/100)
# li=[]
# with open('mcw.txt',mode="r",encoding="utf-8") as f :
#     for line in f:
#         line=line.strip()
#         li.append(line)
# index_li=[]
# for i in range(shang):
#     start_index=i*100
#     end_index=(i+1)*100
#     index=(start_index,end_index)
#     index_li.append(index)
# def func(li,index):
#     print("\n".join(li[index[0]:index[1]]))
# tp=ThreadPoolExecutor(10)
# for i in index_li:
#     t=Thread(target=func,args=(li,i,))
#     t.start()
# tp.shutdown()



# 方法二:
import time
from threading import Thread
from concurrent.futures import ThreadPoolExecutor

# with open('mcw.txt',mode="a",encoding="utf-8") as f :
#     for i in range(0,20000):
#         f.write("魔降風雲變-%s\n"%i)
num_li=[i for i in range(0,20001,100)]#[0, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000, 1100, 1200, 1300, 1400, 1500, 1600, 1700, 1800, 1900, 2000]
cur_li=[]
with open('mcw.txt',mode="rb") as f :
    for i in range(0,20000): #i是0的時候還沒讀取遊标是0,i是第100行(這行還沒讀取)的時候遊标是1990,
        if i in num_li:
            cur=[i,f.tell()]
            cur_li.append(cur)
            print(f.tell())
        data = f.readline()#.strip()
        # data=f.readlines()
        # print(data)
print(cur_li) #[[0, 0], [100, 1990], [200, 4090], [300, 6190], [400, 8290], [500, 10390], [600, 12490],  [1800, 38490], [1900, 40690]]
cur_li_new=[ {"第幾行到第幾行:":"%s到%s行:"%(cur_li[i][0],cur_li[i+1][0]),"seek起始位置:":cur_li[i][1],"read讀取位元組:":cur_li[i+1][1]-cur_li[i][1]}  for i in range(len(cur_li)) if i<len(cur_li)-1]  #,cur_li[i+1][1]-cur_li[i][0]-1):
cur_li_new.append({"第幾行到第幾行:":"%s到%s行:"%(cur_li[-1][0],cur_li[-1][0]+100),"seek起始位置:":cur_li[-1][1],"read讀取位元組:":None})
print(cur_li_new)
def func(i):
    print("-----------%s開始讀取----------------" % i['第幾行到第幾行:'])
    f.seek(i['seek起始位置:'])
    data = f.read(i['read讀取位元組:'])
    print(data.decode())
    time.sleep(0.1)
    print("-----------%s已經結束----------------" % i['第幾行到第幾行:'])
start=time.time()
with open('mcw.txt',mode="rb") as f :
    # tp=ThreadPoolExecutor(10)
    for i in cur_li_new: #單個i元素:{'第一行到第幾行:': '0到100行:', 'seek起始位置:': 0, 'read讀取位元組:': 1990} {'第一行到第幾行:': '100到200行:', 'seek起始位置:': 1990, 'read讀取位元組:': 2100}, {'第一行到第幾行:': '200到300行:', 'seek起始位置:': 4090, 'read讀取位元組:': 2100},
        func(i)
        # Thread(target=func, args=(i,)).start()


    # tp.shutdown()

print(time.time()-start)
# [200, 4090], [300, 6190] seek到4090,read(6190-4090)
#1[0, 0],2 [100, 1990],3 [200, 4090],4 [300, 6190]
# ---------------
#0.0500028133392334   函數執行
#20.00814437866211  線程池執行
#由上可知,實作了線程池效果      

seek定位原理:

  1)讀取第三行,條件一是:需要seek到第三行第一個位元組之前,這個位元組數為第三行之前的位元組總數,即第一第二行的位元組總數,條件二是:我需要讀取的第三行位元組數量

  2)我for循環讀取行數,每次循環f.tell()獲得位元組大小,即讀到第二行獲得第二行之前總的位元組數,讀完第三行獲得第三行及之前的位元組數。由此獲得了條件一

  3)我用前三行的位元組數減去前兩行的位元組數獲得條件2

  4)readline()讀行    tell()擷取讀取了多少位元組  read(位元組數)  seek(位元組數)

注意點:rb讀 保持正确的位元組數。

3.11、tell()擷取第一行位元組數,然後從開頭read這個位元組數擷取内容超過一行的問題

with open('mcw.txt',mode="r",encoding="utf-8") as f :       
# data = f.readline()
# print(data)
# print(f.tell())
# -----結果:
# 魔降風雲變-0
#
# 19      
# 要點一(問題):
# f.seek(0)
# data = f.read(19)
# print(data)
# print(f.tell())
# -------------------結果:
# 魔降風雲變-0
# 魔降風雲變-1
# 魔降風
# 47
# 試了試兩段代碼,第一段代碼是讀取檔案第一行得到第一行總共19個位元組,
# 然後我seek(0),f.read(19)
# 往後讀取19個位元組,預期隻讀取到第一行
# 結果和預期隻列印第一行不同,多列印了47 - 19 = 28
# 個位元組,這是什麼原因呢?
# 是read有問題麼?怎麼看都不想說隻讀取了,難道是編碼問題
# 解答:編碼問題,rb讀取就可以了,想列印就資料.decode()      
with open('mcw.txt',mode="rb") as f       

3.12、f.read(None)

# 要點二:
# f.read(None)從目前指針位置讀取檔案内容到最後