python基礎知識-7-內存、深淺、文件操做

 

python其餘知識目錄html

 

 一、一些對內存深刻理解的案例

如下列舉列表,列表/字典/集合這些可變類型都是同樣的原理python

變量是個地址,指向存儲數據的內存空間的地址,它的實質就至關於c語言裏的指針。變量和數據都存放在內存裏面windows

1.1內存相關的東西 賦值和修改要區別開來,賦值(從新定義)是從新開闢內存,修改是原內存空間內的改變

1.2修改列表元素的底層原理圖解

v1=[1,2,3]
v2=v1
v3=v1
v2,v3指向v1指向的地址,三者指向相同的地址。對變量作修改,修改的是同一個地址的值,三者都變化app

代碼驗證:ide

>>> 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

 

 1.3賦值(從新定義)列表的內存地址變化圖解

v1=[1,2,3]
v2=v1
v3=v1
v2=[1]函數

v2從新定義,內存地址改變post

代碼驗證:學習

>>> 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
View Code

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)編碼

代碼驗證:

>>> 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
View Code

1.7列表中修改不可變元素代碼以及圖解

v1=[1,2,[3,4],5]
v2=v1
v2[0]="mcw"
v2[2][0]="xiaoma"      #原v1[2][0]的值3,若是沒有東西指向它,那就是廢棄的垃圾,垃圾回收機制會將地址回收

代碼驗證:

>>> 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]
View Code

1.8列表中修改可變元素代碼以及圖解

v1=[1,2,[3,4],5]
v2=v1
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

 

二、深拷貝,淺拷貝

可結合上面一些對內存深刻理解的案例進行學習

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

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

代碼驗證:

>>> 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
View Code

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

代碼驗證:

>>> 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
View Code

2.二、#list+set+dict的深淺拷貝

 沒有嵌套的時候:

淺拷貝:拷貝內存地址,即變量名字 只拷貝空殼

深拷貝:找到全部的可變類型數據(數據存放的內存空間)拷貝一份,不可變數據類型不拷貝,獲得的結果同樣   

有嵌套的時候:
淺拷貝:拷貝內存地址,即變量名字,拷貝空殼

深拷貝:找到全部的可變類型數據(數據存放的內存空間)拷貝一份,不可變數據類型不拷貝,獲得的結果同樣。嵌套的把變化的拷貝,某層不變的就不拷貝   

 --------

應該每次都拷貝一份(但因爲小數據池)

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

帶疑問的總結:

淺拷貝:

只拷貝第一層(疑問:拷貝列表,新的列表地址是不一樣的,可是新的列表裏列表元素不管是否
可變,都是指向原有元素的地址?只拷貝第一層的地址指向 思考,那麼只要是淺拷貝的值和地址都是
同樣的嗎,不管列表元素是否可變)(遇到元素不管是否可變都是拷貝的相同的指針)
深拷貝:

拷貝嵌套層次中的全部可變類型(疑問:拷貝列表,新的列表地址變了,內部不變的元素地址
指向原列表元素地址,可是可變的元素會再開闢新的內存地址(新的內存地址中的子元素若是不可變那
麼指向上層的元素的地址,新的內存地址中的子元素若是可變再開闢新的地址,將它自己放在新的地址
,可是子元素的子元素須要再次作判斷 #再次開闢的內存中不變的元素地址和原來仍是相同?))(1
、遇到元素不可變的拷貝元素的指針,二、遇到不可變的就生成新的地址。3假如不可變的裏面還有元素
,對於這裏的元素繼續循環執行第一步和第二部的操做)

2.3深淺拷貝特殊狀況:

元組裏面元素都是不可變的狀況:
v1=(1,2,3,4)
淺:沒有換地址
深:沒有換地址
因爲不可變類型,因此拷貝的時候不改變地址

元組裏面元素有可變的狀況:

元組裏面有可變的,會把元組拷貝一下,元組改變了
v1=(1,2,[1,2,3],4)
淺:沒變
深:變了

三、文件操做:

 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.二、只讀: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.三、只寫:w 只寫權限不能讀。文件不存在則新建

# 打開文件
file_object = open('log.txt',mode='w',encoding='utf-8') # r,read; w,write; a,append;#只寫
打開的話,會先清空,再寫,須要當心。通常用於新建文件

# 寫內容
變量=打開的文件.write("")
# file_object.write('mcw')
# 關閉文件
打開的文件.close()
file_object.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文本,裏面出現內容我是魔降風雲變
5)
file_object = open('mcw.txt',mode='w',encoding='utf-8')
file_object.write('我是小馬過河')
file_object.close()
---------------結果:
沒有輸出,mcw.txt文本里面的「我是魔降風雲變」原內容被新寫的「我是小馬過河」覆蓋掉
6)
file_object = open('mcw.txt',mode='w',encoding='gbk')
file_object.write('我是mcw')
file_object.close()
-------------結果:
將上面的代碼改成encoding="gbk",在Windows上仍是能覆蓋掉原來的內容,打開也能正常的看,沒亂碼

顯示.
七、
沒有讀的權限
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.四、 只追加: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('你好')

# 關閉文件
file_object.close()

使用範例:
1) file_object
= open('mcw.txt',mode='a',encoding='utf-8') file_object.write('我喜歡吃米飯') file_object.close() ---------------結果: 沒有打印輸出,沒有mcw.txt文件。執行代碼後,自動在腳本當前目錄建立文件mcw.txt,並寫入內容: 「我喜歡吃米飯」
2)
file_object = open('mcw.txt',mode='a',encoding='utf-8')
file_object.write(' 我叫小馬過河')
file_object.close()
---------------結果:
已有文件mcw.txt,文件內容爲「我喜歡吃米飯」.執行代碼後,文件內容爲「我喜歡吃米飯 我叫小馬過

河」,追加了「 我叫小馬過河」

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.四、可讀可寫:  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) # 調整光標的位置


content = file_object.read()
file_object.write('浪')

# # 讀取內容
# content = file_object.read()
# print(content)
#
# file_object.write('666')

# 關閉文件
file_object.close()

使用範例:
環境爲:存在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我喜歡吃米飯 我叫小馬過河」
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.五、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)
data = file_object.read()
print(data)
file_object.close()

實驗案例:
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沒有打印出內容。
3file_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.六、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.seek(0)
file_object.write('666')

file_object.close()

實驗案例:
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打印輸出「小馬過河下午,你好呀!」
4)
file_object = open('mcw.txt',mode='a+',encoding='utf-8')
file_object.seek(0)
file_object.write("我很好")
file_object.close()
--------------結果:
後面追加內容了。即便光標移到最前面,只要一寫,不管光標在哪裏都會當即跳到最後而後進行追加內容。試驗代表,追加以後光標在最後須要從新seek調整,否則讀不到內容。

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

讀取文件內容到內存,在內存中修改,點擊保存纔會從新將修改的內容寫入磁盤  打開的文件.read(字符個數,默認爲全部彷佛)

3.七、文件讀操做:

文件讀操做:
設置光標位置,日後讀取幾個字符
file_object = open('mcw.txt',mode='r',encoding='utf-8')

1)讀取文件的全部內容到內存。
若是文件大於內存,那麼內存裝不下所有內容。因此若是之後讀取一個特別大的文件,那就一點一點的

data = file_object.read()

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

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()
----------------結果:
我叫小馬過河
我來自虛空深處。
我來了,但是地球人說,魔降風雲變。

或者:
# 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', '我來了,但是地球人說,魔降風雲變。']

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.八、文件寫操做:

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.close()

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.十、使用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.十一、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.十二、f.read(None)

# 要點二:
# f.read(None)從當前指針位置讀取文件內容到最後
相關文章
相關標籤/搜索