本文是Python通用程式設計系列教程,已全部更新完成,實現的目標是從零基礎開始到精通Python程式語言。本教程不是對Python的內容進行泛泛而談,而是精細化,深入化的講解,共5個階段,25章內容。所以,需要有耐心的學習,才能真正有所收穫。雖不涉及任何框架的使用,但是會對作業系統和網路通訊進行全域性的講解,甚至會對一些開源模組和伺服器進行重寫。學完之後,你所收穫的不僅僅是精通一門Python程式語言,而且具備快速學習其他程式語言的能力,無障礙閱讀所有Python原始碼的能力和對計算機與網路的全面認識。對於零基礎的小白來說,是入門計算機領域並精通一門程式語言的絕佳教材。對於有一定Python基礎的童鞋,相信這套教程會讓你的水平更上一層樓。
一 檔案讀寫基本操作
1. 檔案操作的工作流程
檔案在我們的計算機上隨處可見,當我們需要永久儲存資料的時候就會用到檔案,檔案是由計算機作業系統來提供的,那麼自然也就受作業系統的控制。如下圖所示,一套完整的計算機系統主要由三部分構成:
- 應用程式
- 作業系統
- 計算機底層硬體
2. 檔案操作的基本形式
我們事先在當前路徑下準備好一個檔案a.txt,如下圖所示:
接下來我們在 "檔案處理.py" 檔案內開始寫開啟讀取檔案的操作,在Python中必然會有一個功能或者介面來開啟檔案,這個介面就是open,使用引數如下圖所示: 檔案讀取操作程式碼示例如下:"""
open開啟檔案需要3個引數,
開啟檔案之後會有一個返回值,
讀寫操作就是對這個返回值進行操作
f = open('檔案的路徑',mode='開啟檔案的模式',encoding='操作檔案的字元編碼')
"""
"""
open是向作業系統發請求,會佔用作業系統資源,這個資源不會自動回收
返回值就是應用程式拿到的變數,應用程式的變數Python直譯器會自動幫你回收
"""
# 1 開啟檔案
f = open(r'a.txt',mode='r',encoding='utf-8')
"""
對於應用程式來說上面這行程式碼與我寫一個"f = 1"沒有本質區別,
你不需要再執行"del f",因為直譯器會自動幫你清理這個應用程式資源,
但是,開啟的檔案佔用了作業系統的資源,這不會自動回收
"""
# 2 讀取檔案
data = f.read()
print(data)
# 3 關閉檔案,清理作業系統開啟檔案的資源
f.close()
print(f) # 應用程式的資源還在
# f.read() # 檔案關閉不能再進行讀取
複製程式碼
開啟一個檔案其實是佔用了兩部分資源,分別是作業系統資源和應用程式資源,應用程式資源會自動由Python直譯器來回收,而作業系統開啟檔案的資源並不會立即回收,作業系統每開啟一個檔案其實會有一個編號,每個編號與應用程式向作業系統發起檔案操作請求的編號一一對應,這個編號稱為檔案描述符,作業系統的檔案描述符編號是有限的,所以,當伺服器高併發的時候,由於開啟檔案個數非常多,因而還沒來得及關閉,那麼伺服器就卡了,返回給用的的結果就是使用者的客戶端卡了。
有的時候關閉檔案的操作總是會被遺忘,我們有一個使用 "with"來操作檔案的方式,它是一個上下文的操作,會幫你自動的關閉檔案,程式碼示例如下:
# as 指的是賦值
with open('a.txt', 'r', encoding='utf-8') as f:
data = f.read()
print(data)
複製程式碼
除此之外,“with” 可以連續開啟多個檔案,程式碼示例如下:
with open('a1.txt', 'r', encoding='utf-8') as f1, \
open('a2.txt', 'r', encoding='utf-8') as f2:
data1 = f1.read()
data2 = f2.read()
複製程式碼
二 預設開啟檔案的引數說明
1. 檔案開啟的字元編碼
如果不指定字元編碼,預設開啟檔案的字元編碼與作業系統相匹配:
- Windows系統(中國大陸使用者):gbk
- Liunx系統:utf-8
- MacOS:utf-8
在不指定字元編碼的情況下,MacOS系統示例程式碼:
# 檔案儲存的以utf-8編碼儲存,與本機預設編碼一致
with open('a.txt', 'r', ) as f:
data = f.read()
print(data)
複製程式碼
2. 檔案的開啟模式
檔案預設的開啟模式是“t”模式,指的是文字模式,這意味著在該模式下無法開啟圖片,視訊和音訊等檔案,因為這些是以二進位制格式儲存的,文字模式是以字元形式儲存的。
操作檔案的模式有三種,分別是:“r”,“w”和“a”模式,“r”是隻讀,“w”是隻寫,“a”是指追加,預設操作檔案大模式是“r”模式,所以預設檔案的開啟模式是“rt”模式,對於操作文字檔案,“t”模式必須與操作檔案的三種模式連用,很多時候你看到的,這個“t”經常會省略不寫,這是可以的。
三 文字模式開啟檔案的操作
1. 操作檔案“r”模式
全部讀取使用read,程式碼示例如下:
f = open('a.txt', mode='r', encoding='utf-8') # “r”模式下,如果檔案不存在會報錯
# f.write('哈哈') #丟擲異常,不能寫
print(f.readable()) # 判斷是否可讀
print('=============>1')
print(f.read()) # 全部讀取
print('=============>2')
# 讀檔案會有一個游標移動,第一次讀完了,游標移至末尾,第二次讀無內容
print(f.read())
f.close()
複製程式碼
一行一行讀檔案內容使用readline,程式碼示例如下:
f = open('a.txt', mode='r', encoding='utf-8')
# readline指的是一行一行讀檔案
print(f.readline(), end='') # 檔案中有換行,print也自帶換行,指定end引數去掉預設換行
print(f.readline(), end='')
print(f.readline(), end='')
f.close()
複製程式碼
全部讀取檔案內容,存入列表,每行內容為列表的一個元素使用readlines,程式碼示例如下:
f = open('a.txt', mode='r', encoding='utf-8')
print(f.readlines())
f.close()
複製程式碼
readlines可以加數字作為引數,但是他不是指的行數,而是位元組數,所以我們一般不用,如需逐行列印檔案內容常用readlines與for迴圈連用,程式碼示例如下:
# 如果檔案內容比較少的時候,以下兩種方式都可以
with open('a.txt') as f:
# 當檔案很大時,f.readlines()結果是一個很大的列表在記憶體中,機器就卡了
for line in f.readlines():
print(line, end='')
# 推薦使用這種方式
with open('a.txt') as f: # f是一個可迭代物件,就像老母雞會下蛋一樣
for line in f:
# 檔案內容很大時,使用這種方式每次記憶體中只有一行內容
print(line, end='')
複製程式碼
2. 操作檔案“w”模式
注意:在“w”只寫模式下,當檔案存在時,就會清空該檔案,程式碼示例如下:
f = open(r'a.txt', mode='w', encoding='utf-8') # 預設是wt
f.write('第一行\n') # 需要自己新增“\n”來換行
f.write('第二行\n')
f.close()
複製程式碼
當檔案不存在時,就會建立空文件,程式碼示例如下:
f = open(r'a1.txt', mode='w', encoding='utf-8') # 預設是wt
f.write('第一行\n')
f.write('第二行\n')
f.close()
複製程式碼
只寫模式常用的方法:
f = open(r'a1.txt', mode='w', encoding='utf-8') # 預設是wt
f.writable()
# writelines指的是可以放一個列表或者元組,裡面可以有多行內容,需要自己加換行符
f.writelines(['111111\n', '222222\n', '333333\n'])
# 下面這樣程式碼與上面寫的結果一樣
# f.write('aaaaaa\nbbbbbbb\ncccccc\n')
f.close()
複製程式碼
3. 操作檔案“a”模式
“a”模式指的是隻追加寫,當檔案不存在時,建立空檔案;當檔案存在時,游標直接移至檔案末尾,所以,我們在記錄日誌的時候都會使用“a”模式,程式碼示例如下:
f = open('access.log', mode='a', encoding='utf-8')
print(f.writable())
print(f.readable())
f.write('5555555555555\n')
f.close()
複製程式碼
四 二進位制模式開啟檔案的操作
1. “b”模式基本介紹
“b”模式指的是檔案開啟的模式為“b”模式, 它與“t”模式類似,不能單獨使用,必須以“rb”,“wb”或者“ab”模式來使用,“b”模式讀寫都是以bytes為單位進行的,所以可以理解為“b”模式就是二進位制模式。對於普通文字來說是以字元的形式儲存的,但是對於圖片,視訊或者音訊等等這些檔案則是以二進位制形式儲存的,所以“t”模式無法讀取,程式碼及報錯示例如下:
圖片檔案並不是以字元編碼儲存的,而是以JPG這個格式儲存成了二進位制形式,與字元編碼沒有關係,所以我們以文字模式處理檔案是不可行的。應該以二進位制模式開啟檔案,這時不需要指定字元編碼,正確的開啟方式請看如下程式碼示例:# b模式下一定不能指定encoding引數
with open('01.jpg', 'rb', ) as f:
data = f.read()
print(data)
複製程式碼
2. 操作檔案的“rb”模式
需要說明的一點是,“b”模式也可以讀取文字檔案,字元的底層都是以二進位制形式儲存的,只不過你在使用“t”模式讀取文字檔案的時候open幫你把二進位制轉成了能夠看懂的文字,這是“t”模式的便利之處,但是它有侷限性,只能操作文字檔案,而“b”模式具有統一性,任何檔案底層儲存原理都是二進位制,這也就是意味著“b”模式可以操作任何檔案,程式碼示例如下:
with open('01.jpg', 'rb', ) as f1, open('a.txt', 'rb') as f2:
img = f1.read()
text = f2.read()
print(text.decode('utf-8')) # 把bytes轉化成utf-8
複製程式碼
3. 操作檔案的“wb”模式
“wb”模式也是操作檔案“w”模式的一種,當檔案存在時,就會清空該檔案,當檔案不存在時,就會建立空檔案,程式碼示例如下:
# wb模式寫入
with open('a.txt', 'wb') as f:
msg = '你好,世界'
f.write(msg.encode('utf-8')) # 指定寫入檔案的字元編碼
# rb模式讀取
with open('a.txt', 'rb') as f:
data = f.read()
print(data)
print(type(data))
print(data.decode('utf-8')) # 指定讀取檔案的字元編碼
複製程式碼
4. 操作檔案的“ab”模式
“ab”模式指的是以二進位制形式追加寫,與操作檔案的“a”模式同理,程式碼示例如下:
with open('a.txt', 'ab') as f:
msg = '\n世界:你也好,小鬼'
f.write(msg.encode('utf-8')) # 指定寫入檔案的字元編碼
複製程式碼
補充: 在這這裡講一個小模組的部分用法,是sys模組,它的使用說明請看下面程式碼示例和截圖:
import sys # 首先匯入這個模組
list_test = sys.argv # 它的返回值是一個列表
print(list_test)
複製程式碼
接下來我們在終端環境下執行以下命令(注意引數1前後的空格):
你可以看到在終端執行列印的結果就是一個列表,第一個值是檔案路徑,第二個和第三個值分別是兩個引數。5. 操作檔案的其他模式(瞭解)
一般來說,你遇到的操作檔案的模式都是隻讀或者只寫,但是也有可讀可寫的模式,這類模式瞭解即可,說明和程式碼示例如下:
# "r+t"模式,或者寫成"r+"模式,指的是可讀可寫
with open('a.txt', 'r+t', encoding='utf-8') as f:
print(f.readable())
print(f.writable())
# "w+r"或者"w+"模式,可讀可寫
with open('a.txt', 'w+t', encoding='utf-8') as f:
print(f.readable())
print(f.writable())
# "a+t"或者"a+",可讀可追加寫
with open('a.txt', 'a+t', encoding='utf-8') as f:
print(f.readable())
print(f.writable())
# "U"模式,通用換行符,已廢棄,無需瞭解
# with open('a.txt', 'U', encoding='utf-8') as f:
# print(f.readable())
# print(f.writable())
複製程式碼
“r+”與“w+”,“a+”模式都是可讀可寫,他們的區別在於不改變自身原本操作檔案的形式,即“r+”模式下,當檔案不存在會儲存,“w+”或者“a+”模式當檔案不存在會建立新檔案,當檔案存在會清空檔案。
五 檔案內游標移動
在開啟檔案時會有一個游標移動,我們使用seek這個方法,可以實現游標的移動,程式碼示例如下:
with open('a.txt', 'r') as f:
f.seek(9) # 這個引數指的是偏移量,以位元組為單位
data = f.read()
print(data)
複製程式碼
注意:游標移動只能是從左往右移動,seek可以加兩個引數,第一個引數就是上面程式碼中的引數,你如果只傳一個引數也就是指的這個引數,第二個引數預設是0,指的是游標在檔案開頭位置開始移動,除了0之外,只能接收1或者2作為引數,1表示從當前位置開始移動,2表示從檔案末尾開始移動,其中1和2必須在“b”模式下進行,0可以在“t”模式或者“b”下都能執行,但是無論哪種模式,都是以bytes為單位進行的,程式碼示例如下:
with open('a.txt', 'rb') as f:
f.seek(3, 0) # 移動三個位元組,也就是utf-8編碼下一個中文字元
print(f.tell()) # 當前游標位置,以位元組為單位
f.seek(3, 1) # 從當前位置向右偏移3個位元組然後再讀取檔案內容
# f.seek(3, 2) # 只能讀取動態資料新新增的內容
data = f.read()
print(data.decode('utf-8'))
with open('a.txt', 'r') as f:
f.seek(3, 0)
print(f.read())
複製程式碼
補充: 在這裡補充一個小模組的用法,是os模組,它的使用說明請看下面程式碼示例:
import os # 首先匯入這個模組
os.rename('a.txt', 'b.txt') # 修改檔名,兩個引數分別為原始檔名和目標檔名
os.remove('a1.txt') # 刪除a1.txt檔案,這個引數指的是檔案路徑
複製程式碼