文件操作
馮諾依曼體系架構
CPU由運算器和控制器組成
運算器,完成各種算數的運算,邏輯運算,數據傳輸等數據加工處理
控制器,控制程序的執行
存儲器,用于記憶程序的數據,列如內存
輸入設備,將數據或者程序輸入到計算機中列如鍵盤 鼠標
輸出設備,將數據或者程序的處理結果展示給用戶,列如顯示器,打印機等等
?
一般說的IO操作,指的是文件的IO,如果是指網絡的IO都會直接說網絡IO
文件的IO常操作
open—-打開 ??read—-讀取 ???寫入—-write ?close—–關閉
readline—行讀取 ??readlines—-多行讀取 ??seek—-文件指針操作 ??tell—指針位置
打開操作
open(file,mode=’r’,buffering=-1,encoding=None,errors=None,newline=None,closefd=True,opener=None)
打開一個文件,返回一個文件對象和文件的描述符。打開文件失敗,則返回異常
基本使用:
創建一個文件test,然后打開它,用完關閉
f = open(‘test’)
print(f.read())
f.close()
文件操作中,最常用的操作就是讀寫
文件的訪問操作的模式有兩種:文本模式和二進制模式。不同的模式下,函數的操作不盡相同。表現結果也不一樣
open的參數
file 打開或者要創建的文件名,如果指定路徑。默認是當前路徑
Mode模式
r 缺省的,表示只讀打開
w ??只寫打開
x 創建并寫入一個新的文件
a 寫入打開,如果文件存在,則追加
b 二進制模式
t 缺省的文本模式
+ 讀寫打開一個文件,給原來只讀只寫方式打開提供缺失的讀或者寫的能力
練習:
#r模式
f = open(‘test’,’r+’)
f.read()
f.write(‘abc’)
f.close()
print(f)
?
f = open(‘test’,’w+’)
f.read()
f.write(‘123’)
f.close()
open默認是只讀模式r打開已經存在的文件
R
只讀打開文件,則用write方法會拋異常
如果文件不存在,拋出FileNotFoundError異常
?
W
如果只寫方式打開,如果讀則拋出異常
如果文件不存在,則直接創建文件
如果文件存在,則清空文件內容
f = open(‘test1′,’x’)
f.write(‘abc’)
f.close()
X
文件不存在則創建文件,并以只讀方式打開
文件存在,拋出FileExisError異常
A
文件存在。只寫打開,追加內容
文件不存在,則創建后,只寫打開,追加內容
r是只讀,wxa都是只寫
Wxa都可以產生新的文件w不管文件存在與否,都會生成全新內容得文件,a不管文件是否存在,都能在打開的文件內部追加,x必須要求文件事先不存在,自己創造一個新的文件
文本模式t
字符流,將文件的的字節按照某種字符編碼理解,按照字符操作,open的默認mode就是rt
二進制模式b
字節流,將文件就按照字節理解,與字符編碼無關,二進制模式操作時,字節操作使用bytes類型
f = open(“test”,’rb’)
s = f.read()
print(type(s))
print(s)
f.close()
f = open(‘test’,’wb’)
s = f.write(“馬哥教育”.encode())
print(s)
f.close()
?
f = open(“test”,’r+’)
s = f.read()
f.write(“馬哥教育”)
print(f.read())
f.close()
?
+
為 r,w,a,x提供缺失的讀寫功能,但是,獲取的文件對象依舊按照r,w,a,x自己的特征。+不能單獨使用,可以認為他是為前面的模式字符做增強功能的
文件指針
上面的例子中,已經說明了有一個指針
文件指針,指向當前字節位置
mode=r 指針的起始位置在0
mode=a 指針的起始位置在EOF
tell()顯示指針當前的位置
seek(offset[,whence])
移動文件指針位置,offest偏移多少字節,只能是正整數
文本模式下
whence 0 缺省值,表示從頭開始,offest只能是正整數
whence 1 表示從當前位置,offest只接受0
whence 2 表示從EOF開始,offest只接受0
文本模式支持從頭開始向后偏移的方式
Whence為1表示從當前位置開始偏移,但是只支持偏移0,相當于原地不動,所以沒什么用
Whence為2表示從EOF開始,只支持偏移0,相當于移動文件指針到EOF
Seek是按照字節偏移的
二進制模式下
Whence 0 缺省值,表示從開頭開始,offest只能說正整數
Whence 1 表示從當前位置,offest可正可負
Whence 2 表示從EOF開始,offes可正可負
二進制模式支持任意起點的偏移,從頭,叢尾,從中間位置開始
向后seek可以超界,但是向前seek的時候不能超界,不能超界,否則拋異常
Buffering:緩沖區
-1 表示使用缺省大小的buffer,如果是二進制模式,使用io.DEFAULT_BUFFER_SIZE值,默認是4096或者8192.如果是文本模式,如果是文本模式,如果是終端設備,是行緩寸模式,如果不是,則使用二進制模式策略
0只在二進制模式使用,表示關buffer
1 只在文本模式使用,表示行緩沖,意思就是見到換行符就flush
大于1用于指定buffer的大小
Buffer緩沖區
緩沖區一個內存空間,一般來說是一個FIFO隊列,到了緩沖區慢了或者達到閾值,數據才會flush到磁盤
Flush()將緩沖區數據寫入磁盤
Close()關閉前會調用flush()
Io.DEFAULT.BUFFER_SIZE缺省緩沖區大小字節
二進制模式
?
import io
f = open(‘test’,’w+b’)
print(io.DEFAULT_BUFFER_SIZE)
f.write(“magedu.com”.encode())
f.seek(0)
f.write(“www.magedu.com”.encode())
f.flush()
f.close()
f = open(“test4″,’w+b’,4)
f.write(b”mage”)
f.write(b”du”)
f.close()
文本模式
f = open(“test”,’w+’,1)
f.write(“mag”)
f.write(“magedu”*4)
f.write(‘\n’)
f.write(“hello\npython”)
f.close()
?
import io
f = open(‘test’,”w+”,15)
f.write(“mage”)
f.write(“du”)
f.write(‘hello\n’)
f.write(‘\npython’)
f.write(‘a’*(io.DEFAULT_BUFFER_SIZE – 20))
f.write(“\nwww.magedu.com/python”)
?
Buffering = 0
這是一種特殊的二進制模式,不要內存的buffer,可以看做是一個FIFO的文件
f = open(‘test’,”wb+”,0)
f.write(b’m’)
f.write(b’a’)
f.write(b”g”)
#f.write(b.’magedu*4′)
f.write(b’\n’)
#f.write(b.’hello\npython’)
f.close()
?
Buffering = -1 t和b,都是io.DEFAULT_BUFFER_SIZE
Buffering = 0 b關閉緩沖區t不支持
Buffering = 1 b就一個字節,t行緩沖,遇到換行符才flush
Buffering > 1 b模式表示行緩沖值的大小,緩沖區的值可以超過io.DEFAULT_BUFFER_SIZE直到設定的值超過后才把緩沖flus。t模式,是io.DEFAULT_BUFFER_SIZE,flush完成后吧當前字符串也寫入磁盤
似乎看起來很麻煩,一般來說,只需要記得:
文本模式,一般都用默認緩沖區大小
二進制模式,是一個個字節的操作,可以指定buffer的大小
一般來說,默認緩沖區大小是個比較好的選擇,除非明確知道,否則不能調整它
一般編程中,明確知道需要寫磁盤了,都會手動調用榆次flush,而不是等到自動flush或者close的時候
Encoding:編碼,僅文本模式使用
None表示缺省編碼,依賴于操作系統,Windows,linux測試如下代碼
f = open(‘test’,’w’)
f.write(‘啊’)
f.close()
?
Windows下缺省GBK(0xB0A1),LINUX下缺省UTF-8(0xE5 95 8A)
其他參數
Error
什么樣的編碼將被捕獲
None和strict表示有編碼錯誤將拋出ValueError異常:ignore表示忽略
Newline
文本模式中,換行的轉換,可以轉換為None,’’空子串,’\r’?, ‘\n’?, ‘\r\n’
讀時。None表示’\r’?, ‘\n’?, ‘\r\n’都會被轉換為’\n’:表示不會自動轉換通用換行符,其他合法字符表示換行符就是指定字符,就會按照指定字符分行
寫時,None表示’\n’都會被替換為系統缺省行分隔符os.linesep : ‘\n’?或表示’\n’不替換:其他合法字符表示’\n’會被替換為指定的字符
f = open(‘test’,’w’)
f.write(‘python\rwww.python.org\nwww.magedu.com\r\npython3′)
f.close()
newline = [None,”,’\n’,’\r\n’]
for nl in newline:
f = open(‘test’,’r+’,newline=nl)
print(f.readline())
f.close()
Closefd
關閉文件描述符,True表示關閉它,False會在文件關閉后保持這個描述符。fileobj.fileno()查看
Read
Size表示讀取的多少個字符的字節,負數或者None表示讀取到EOF
f = open(‘test’,’r+’,0)
f.write(“magedu”)
f.write(‘\n’)
f.write(‘馬哥教育’)
f.seek(0)
f.read(7)
f.close()
f = open(‘test’,’rb+’)
f.read(7)
f.read(1)
f.close()
行讀取
Readline(size = -1)
一行行讀取文件內容。Size設置一次能讀取行內幾個字符或字節。
Readline(hint = -1)
讀取所有行的列表。指定hint則返回指定的行數
f = open(‘test’)
for line in f:
print(line)
f.close()
Write(s),把子串s寫入到文件中并返回字符的個數
Writeline(lines),將字符串列表寫入文件
f = open(‘test’,’w+’)
lines = [‘abc’,’123\n’,’magedu’]
f.writelines(lines)
f.seek(0)
print(f.read())
f.close()
Close
Flush并關閉文件對象
文件已經關閉,再次沒有任何效果
其他
Seekable()是否可seek
Readable()是否可讀
Writeable()是否可寫
Closed 是否已經關閉
上下文管理
問題的引出
?
lst = []
for _ in range(2000):
lst.append(open(‘test’))
print(len(lst))
Lsof列出打開的文件,就沒有#yum install lsof
$ lsof -p 1427 | grep test | wc -l
Lsof -p 進程號
Ulimit -a 查看所有限制,其中openfile就是打開文件的次數,默認1024
for x in lst:
x.close()
1,異常處理
當出現異常的時候,攔截異常,但是因為很多代碼都可能出現OSError異常,還不好判斷就是因為資源限制產生的
f = open(‘test’)
try:
f.write(‘abc’)#文件只讀,寫入失敗
finally:
f.close()#這個可以
使用它finally可以保證打開的文件可以被關閉
2.?上下文管理
一種特殊的語法,交給解釋器去釋放文件對象
del f
with open(‘test’) as f:
f.write(‘abc’)#文件只讀寫入失敗
f.close()
?
使用with ……as 關鍵字
上下文的管理的語句塊并不會開啟新的作用域
With語句塊執行完的時候,會關閉文件對象
f = open(‘test’)
with f:
f.write(“abc”)
f.close()
?
對于類似于文件對象的IO對象,一般來說都需要在不使用的時候關閉注銷,釋放資源
IO被打開的時候,會獲取一個文件描述符,計算機的資源是有限的,所以操作系統都會做限制
練習
指定一個源文件,實現copy到目標目錄。
filename1 = ‘tmp/test.txt’
filename2 = ‘tmp/test1.txt’
f = open(filename1,’w+’)
lines = [‘abc’,’123′,’namgedu’]
f.writelines(‘\n’.join(lines))
f.seek(0)
print(f.read())
f.close()
def copy(src,dest):
with open(src) as f1:
with open(dest, ‘w’) as f2:
f2.writel(f1.read())
copy(filename1,filename2)
?
有一個文件,對其單詞進行統計,不區分大小寫,并顯示單詞重復最多的10個單詞
d = {}
with open(‘sample’,encoding=’utf-8′) as f:
for line in f:
words = line.split()
for word in map(str.lower,words)
d[word] = d.get(word,0)+1
print(sorted(d.items(),key=lambda item:item[1],reverse=True))?
本文來自投稿,不代表Linux運維部落立場,如若轉載,請注明出處:http://www.www58058.com/97340