文件處理之open()功能的使用
一、引入
什么是文件?
文件是操作系統(tǒng)提供給用戶或者是應用程序用于操作硬盤的虛擬概念或者說接口。
為什么要有文件?
用戶通過應用程序可以通過文件,將數(shù)據(jù)永久保存到硬盤中。
詳細的說:用戶和應用程序操作的是文件,對文件的所有操作,都是向操作系統(tǒng)發(fā)送系統(tǒng)調(diào)用,然后再由操作系統(tǒng)將其轉(zhuǎn)換成具體的硬盤的操作。
二、文件操作的基本流程
基本流程
偽代碼實例:
f = open(r'指定你要打開文件的文件路徑', mode='rt,)
r:
raw_str,指的是原生得字符串,里面得反斜杠\,都會被視為普通字符。
windows中路徑分隔符解決方案:
方案一(推薦):在文件路徑前加r
方案二:windows中會把左斜杠/,默認轉(zhuǎn)換成右斜杠\。使用 'C:/a.txt/nb/c/d.txt',默認會轉(zhuǎn)成 'C:\a.txt\nb\c\d.txt'。
絕對路徑與相對路徑:
相對路徑:會以你當前執(zhí)行文件所在的文件夾下為基準去找。
? 優(yōu)點:簡潔
? 缺點:當你執(zhí)行文件移動,被操作文件將找不到。
絕對路徑:從盤符的根目錄下開始直接定位到你需要操作的文件地址。
優(yōu)點:執(zhí)行文件移動到任意目錄中都可以找到所需要操作的文件地址。
缺點:臃腫
rt:
默認控制文件讀寫操作的模式是r,只讀模式。
默認控制文件讀寫內(nèi)容的模式是t,t文本模式。
原理解析:
? ?f = open 占用了2部分的內(nèi)存空間:
? 第一部分:open占用的是操作系統(tǒng)的的內(nèi)存空間。由操作系統(tǒng)的映射到了應用程序的內(nèi)存空間中。
第二部分:我們知道f的值是一種變量,而變量都是歸屬于python的內(nèi)存空間,也就是說。f占用的就是應用程序的內(nèi)存空間。
操作文件的基本流程:
# 1、打開文件
f = open(r'aaa/a.txt', mode='rt') # open是向操作系統(tǒng)發(fā)起系統(tǒng)調(diào)用。
?
# 2、操作文件:讀寫/文件
res = f.read() # f.read()向操作系統(tǒng)發(fā)送請求,讓操作系統(tǒng)把文件從硬盤讀入內(nèi)存。
print(res)
?
# 3、關閉文件
f.close() ?# 告訴操作系統(tǒng),回收剛剛讀入文件內(nèi)存占用的內(nèi)存空間。(需要考慮的操作:操作系統(tǒng)打開文件,如果沒有及時關閉,就會無意義的占用操作系統(tǒng)的內(nèi)存空間,并且還會無意義的占用操作系統(tǒng)的操作文件數(shù)。如果沒有指定關閉,操作系統(tǒng)不會立即清除該內(nèi)存空間的占用,只有過了一定的時間,操作系統(tǒng)才會把沒有意義的占用清除,而這種清除時間間隔對于我們來說感覺不到,但是對于計算機來說,是非常大的損耗。補充:操作系統(tǒng)打開文件的文件是有限的,如果開打文件過多,就會影響你的電腦性能。)
?
f.read() ?# 注意:f.close()之后,不能在對文件進行操作了。這個時候操作系統(tǒng)已經(jīng)把調(diào)用的文件關閉回收了,如果繼續(xù)調(diào)用就會報錯(ValueError: I/O operation on closed file.)。
?
del f ?# 注意:del f 的順序要放在f.close()后面。(不需要考慮的操作:有python的GC機制管理)
資源回收與with上下文管理
引入:
with
稱之為:上下文管理,上文幫你打開文件,下文幫你關閉文件。
強調(diào):
open
對應的賦值對象f,稱之為文件對象、又有人稱之為‘文件句柄’(柄:游戲手柄干嘛的?就是用來操作游戲的。那么我也也可以推理出,其實‘文件句柄’,就是用來遠程控制文件的。)
打開一個文件包含兩部分資源:應用程序的變量f和操作系統(tǒng)打開的文件。在操作完畢一個文件時,必須把與該文件的這兩部分資源全部回收,回收方法為:
1、f.close() #回收操作系統(tǒng)打開的文件資源
2、del f #回收應用程序級的變量
其中del f
一定要在f.closs()
之后,否則就會導致系統(tǒng)文件打開無法關閉,白白占用了資源,而python
自動的垃圾回收機制決定了我們無需考慮del f,這就要求我們,在操作完畢文件后,一定要記住f.close()
,雖然我們?nèi)绱藦娬{(diào),但是大多數(shù)讀者還是會不由自主地忘記f.close()
,考慮到這一點,python提供了with關鍵字來幫我們管理上下文
# 1、with打開單個文件
with open('a.txt', mode='rt') as f:
? ?res = f.read()
? ?print(res)
# 上面沒有指定f.close(), with會等其子代碼塊群不運行完畢以后,會幫你自動調(diào)用f.close()。
?
?
# 2、with同時打開多個文件,用逗號分隔開即可
# with open('a.txt', mode='rt') as f1, open('b.txt', mode='rt') as f2: # 當你的一行代碼過長,可以使用右斜杠\(注意:右斜杠\并不是換行,而是轉(zhuǎn)義且分隔。)
with open('a.txt', mode='rt') as f1, \
? ? ? ?open('b.txt', mode='rt') as f2:
? ?res1 = f1.read()
? ?res2 = f2.read()
? ?print(res1)
? ?print(res2)
指定操作文本文件的字符編碼
-
上面沒有指定操作文本的字符編碼,接下來我們需要指定:
f = open(...)是由操作系統(tǒng)打開文件,如果打開的是文本文件,會涉及到字符編碼問題,如果沒有為open指定編碼,那么打開文本文件的默認編碼很明顯是操作系統(tǒng)說了算了,操作系統(tǒng)會用自己的默認編碼去打開文件,在windows下是gbk,在linux下是utf-8。 這就用到了字符編碼的問題:若要保證不亂碼,文件以什么方式存的,就要以什么方式打開。 ? f = open('a.txt','r',encoding='utf-8') ?
文件的操作模式
控制文件讀寫的操作模式
-
r(默認的)
:只讀 -
w:只寫
-
a
:之追加寫
r
模式的使用:只讀模式
特點:當文件不存在時,r模式會報錯。當文件存在時,文件指針跳到開始位置,也就是說從文件開頭位置開始。只能讀,不能寫。
""""
先手動創(chuàng)建c.txt文件文件,文件內(nèi)容如下:
哈哈哈哈
""""
# 1、以t模式為基礎進行內(nèi)存操作
with open('c.txt', mode='rt', encoding='utf-8') as f:
? ?print('res'.center(50, '-'))
? ?res = f.read() ?# 執(zhí)行f.read(),文件指針從開頭一下子跳到文件末尾,同時也把文件內(nèi)容一次性由硬盤讀入內(nèi)存。問題? 當文件過大時,會把內(nèi)存干懵!?。?/span>
? ?print(res)
?
? ?print('res1'.center(50, '-'))
? ?res1 = f.read() ?# 注意:上面執(zhí)行了f.read()操作,文件指針在末尾,這個時候怎么讀。都讀不出來了。
? ?print(res1)
?
? ?# 注意:上面讀出文件的每行內(nèi)容,在每行內(nèi)容末尾都有個換行符\n。
'''
-----------------------res------------------------
哈哈哈哈
-----------------------res1-----------------------
'''
? ?
# 2、案例:優(yōu)化之前的用戶登錄操作,之前的用戶站賬戶信息不能永久保存,這里我們通過存入文件將用戶賬戶信息永久保存。網(wǎng)址連接(第9題:編寫用戶登錄接口寫法一):https://www.cnblogs.com/yang1333/p/12357167.html
# 經(jīng)驗總結(jié):for+else,用于用戶登錄功能中時,else中的子代碼塊放用戶登錄失敗以后的打印信息。要知道用戶登錄成功,一定是break退出循環(huán),這個else錯誤信息也就不執(zhí)行,也沒有執(zhí)行的必要。但是反過來說,用戶登錄失敗,break語句也就一定不會執(zhí)行到,那么else中的子代碼塊的執(zhí)行,也就不會被break打段。
'''
先手動創(chuàng)建user.txt文件文件,文件內(nèi)容如下:
egon:123
lili:456
jack:777
tom:666
'''
inp_username = input("please input your username>>:").strip()
inp_password = input("please input your password>>:").strip()
?
with open('user.txt', mode='rt', encoding='utf-8') as f:
? ?for line in f: ?# 遍歷文件對象,line取出的是文件中的每1行的內(nèi)容。(注意:取出的內(nèi)容都是str類型,且每一行的末尾都有換行符\n,直接打印print(line)看不到,所以下面使用print([line])放入列表中顯示)
? ? ? ?# print([line])
? ? ? ?# line.split() # 注意:不能直接使用split(),因為文件每行內(nèi)容末尾(除了最后1行文件內(nèi)容沒有換行符)都有換行符\n,我們要像下面?一樣先使用strip()去除\n。
? ? ? ?res = line.strip() ?# 使用strip()默認不加參數(shù),去除空白,需要注意的是 \n這個換行符也叫空白符,也可以去除。
? ? ? ?# print([res])
?
? ? ? ?# 使用split(':')切分字符串,轉(zhuǎn)換成列表。第一個值作為用戶賬號,第二個值作為用戶密碼。
? ? ? ?username, password = res.split(':')
? ? ? ?if username == inp_username and password == inp_password:
? ? ? ? ? ?print('登錄成功!')
? ? ? ? ? ?break
? ?else:
? ? ? ?print('登陸失??!賬號或密碼錯誤!')
w
模式的使用:只寫模式
特點:只寫模式,當文件不存在時,會創(chuàng)建空文件。當文件存在時,會清空文件。文件指針位于開始位置。不可讀,只能寫。
強調(diào):
-
在文件不關閉的情況下,連續(xù)的寫入,后寫的內(nèi)容一定跟在前寫內(nèi)容的后面
-
如果重新以w模式打開文件,則會清空文件內(nèi)容
# 1、引入
with open('d.txt', mode='wt', encoding='utf-8') as f:
? ?# f.read() # 不可讀,只能寫。
? ?f.write('哈哈哈哈我擦嘞\n') ?# 注意:每一次運行,在w模式下,都會先清空原內(nèi)容。文件指針位于開始位置。(提示:這里的\n是位-------)
'''
d.txt文件中顯示結(jié)果:
哈哈哈哈我擦嘞
?
''' ? ?
? ?
# 1.1 強調(diào)1:w模式打開文件沒有關閉的情況下,連續(xù)的寫,新的內(nèi)存總是更在舊的之后。
with open('d.txt', mode='wt', encoding='utf-8') as f:
? ?f.write('我擦嘞1\n')
? ?f.write('我擦嘞2\n')
? ?f.write('我擦嘞3\n')
'''
d.txt文件中顯示結(jié)果:
我擦嘞1
我擦嘞2
我擦嘞3
?
'''
? ?
# 1.2 強調(diào)2:重新以w模式開打文件,則會先清空文件內(nèi)容。
with open('d.txt', mode='wt', encoding='utf-8') as f:
? ?f.write('我擦嘞1\n')
with open('d.txt', mode='wt', encoding='utf-8') as f:
? ?f.write('我擦嘞2\n') ? ?
with open('d.txt', mode='wt', encoding='utf-8') as f:
? ?f.write('我擦嘞3\n')
# 以上內(nèi)容,d.txt文件中,只有:我擦嘞3\n
?
# 2、案例:w模式用來創(chuàng)建全新文件(應用:文件與文件的copy工具)
'''
# 2.1 下面的內(nèi)容屬于拓展內(nèi)容:(注意:如果該內(nèi)容沒有添加,必須保證輸入的源路徑存在,沒有存在,程序則會報錯。)
import os
?
source_file = input("源文件路徑>>:").strip()
destination_file = input("目標路徑>>:").strip()
?
# 先判斷源文件路徑在不在,不在幫助用戶在指定路徑下創(chuàng)建源文件及其內(nèi)容
if not os.path.isfile(source_file):
? with open(r'{}'.format(source_file), mode='wt', encoding="utf-8") as f:
? ? ? for i in range(4):
? ? ? ? ? f.write('我擦嘞:%s\n' % i)
'''
?
# 2.2 實際內(nèi)容:
with open(r'{}'.format(source_file), mode='rt', encoding='utf-8') as f,\
? ? ? ?open(r'{}'.format(destination_file), mode='wt', encoding='utf-8') as f1:
? ?# 將讀出的源文件內(nèi)容,寫入用戶指定的目標件中
? ?# source_file_content = f.read()
? ?# f1.write(source_file_content)
?
? ?# 優(yōu)化:?上面2步我們發(fā)現(xiàn)使用的是f.read(),它是一下子把文件從硬盤讀入內(nèi)存,如果文件過大,會把內(nèi)存干懵逼!
? ?for line in f:
? ? ? ?f1.write(line) ? ? ? ?
a
模式的使用:只追加寫模式
特點:只追加寫。在文件不存在時,會創(chuàng)建空文檔,文件指針只能在開頭,其實這里的開頭也是末尾。在文件存在時,文件指針會直接跳到文件內(nèi)容末尾。不能讀,只能追加寫。
總結(jié):a模式與w模式區(qū)別以及a模式與w模式作用如下:
a模式與w模式區(qū)別:
-
相同之處:在文件打開不關閉的情況下,連續(xù)的寫入,新寫的內(nèi)容總會跟在之前寫的內(nèi)容之后。
-
不同之處:a模式重新開打文件,只要打開文件,它的指針就會跳到末尾。w模式重新打開文件,直接清空文件。
a模式與w模式作用:
-
w模式用來創(chuàng)建新文件。(通常用來copy文件) 文章來源:http://www.zghlxwxcb.cn/news/detail-403133.html
-
a模式爭對老文件。(通常用來記錄日志文件,通常用與用戶注冊)文章來源地址http://www.zghlxwxcb.cn/news/detail-403133.html
# 1、引入
with open('e.txt', mode='at', encoding='utf-8') as f:
? ?f.write('我擦嘞1\n')
? ?f.write('我擦嘞2\n')
? ?f.write('我擦嘞3\n') ?
?
# 2、a模式案例:實現(xiàn)用戶注冊功能(每來一個用戶,打開文件,把新用戶的信息追加寫到已存在的用戶賬戶末尾。)
"""
# 2.1 下面的內(nèi)容屬于拓展內(nèi)容:
import os
?
if not os.path.isfile('user.txt'):
? with open(r'user.txt', mode='wt', encoding='utf-8') as f:
? ? ? f.write('egon:123\nalex:alex3714\n')
?
register = False
while True:
? username = input('請輸入注冊賬號>>:').strip()
? password = input('請輸入注冊密碼>>:').strip()
? confirm_password = input('請確認注冊密碼>>:').strip()
?
? # 如果username,password,confirm_password有一個為空那么讓用戶重新注冊
? if '' in [username, password, confirm_password]:
? ? ? print('注冊賬號、注冊密碼、確認注冊密碼不能為空。')
? ? ? continue
? # 如果用戶2次密碼不一致,那么讓用戶重新注冊
? if password != confirm_password:
? ? ? print('用戶2次密碼不一致')
? ? ? continue
? ? ? # 如果用戶以及存在,那么讓用戶重新注冊
? with open(r'user.txt', mode='rt', encoding='utf-8') as f:
? ? ? for line in f:
? ? ? ? ? if username == line.strip().split(':')[0]:
? ? ? ? ? ? ? print('用戶已經(jīng)存在,重新注冊')
? ? ? ? ? ? ? break
? ? ? else:
? ? ? ? ? register = True
? ? ? ? ? print('正在為您注冊中'.center(50, '-'))
? ? ? ? ? import time
? ? ? ? ? time.sleep(2)
? if not register:
? ? ? continue
?
? # 用戶注冊滿足條件,寫入文件,注冊該用戶
? with open(r'user.txt', mode='at', encoding="utf-8") as f:
? ? ? f.write('{}:{}\n'.format(username, password))
? print('恭喜你!注冊成功!'.center(50, '-'))
? break
"""
?
# 2.2 實際內(nèi)容:
username = input('your useranem>>:').strip()
password = input('your password>>:').strip()
with open(r'db.txt', mode='at', encoding='utf-8') as f:
? ?f.write(f'{username}:{password}\n')
+ 模式的使用(了解):r+、w+、a+模式
# r+ w+ a+ :可讀可寫
#在平時工作中,我們只單純使用r/w/a,要么只讀,要么只寫,一般不用可讀可寫的模式
"""
注意:+不能單獨使用,必須配合r、w、a
"""
# 1、r+模式:以r基準,g.txt文件不存在,直接就報錯
'''
提前創(chuàng)建user.txt文件,寫入以下內(nèi)容:
111
222
333
444
5555
444
5555
?
中國
中國
中國
?
'''
with open('g.txt', mode='rt+', encoding='utf-8') as f:
? ?print(f.read()) ?
? ?f.write('中國\n') ?# 如果上面執(zhí)行了f.read()操作,文件指針默認就會移動到文件末尾,f.write('中國\n')操作就會把內(nèi)容寫入到文件末尾。(類似于a操作)如果上面沒有執(zhí)行f.read()操作,文件指針默認在開始位置,輸入的內(nèi)容多少,就會把g.txt中的原內(nèi)容覆蓋多少。
?
# 2、w+模式:以w基準
with open('h.txt', mode='w+t', encoding='utf-8') as f:
? ?f.write('111\n')
? ?f.write('222\n')
? ?f.write('333\n')
? ?# w模式打開文件,清空源文件,文件指針在起始位置。以上f.write操作會按照先后順序?qū)懭雋.tx文件。
? ?print('=======>', f.read())
? ?# ?上面使用f.read()操作,這個時候文件指針在末尾,并不能讀出任何內(nèi)容。
?
# 3、a+模式:以a基準 ? ?
with open('g.txt',mode='at+',encoding='utf-8') as f:
? ?# print('f.read()') # a模式下,一打開文件,文件指針就在末尾。f.read()操作并不能讀出任何文件內(nèi)容。
? ?f.write('中國') ?# 更具上面得知文件指針就在末尾,f.write操作會把輸入的內(nèi)容追加到文件內(nèi)容的末尾去。
到了這里,關于python文件處理之open()功能的使用part1的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!