python的文件操作
1、什么是文件
文件是操作提供給用戶/應用程序存取硬盤的一種機制
2、為何要用文件
永久保存數據
3、代碼如何操作文件
關鍵字open()
三步走:
1.利用關鍵字open打開文件
2.利用其它方法操作文件
3.關閉文件
文件路徑
相對路徑與絕對路徑
所謂相對路徑,就是相對於自己的目標文件位置。
相對路徑:
絕對路徑:
路徑中出現了字母與斜杠的組合產生了特殊含義如何取消?
在路徑字符串前面加一個r
r'D:\pycharm\測試\a.txt'
其中如果打開一個文件,需要這三個參數:
open(文件路徑,讀寫模式,字符編碼)
文件路徑與讀寫模式是必須的
字符編碼是可選的(有些模式需要編碼)
res = open('a.txt', 'r', encoding='utf8')
文件運行的流程是這樣的。
打開文件,由應用程序向操作系統發起系統調用open(...),操作系統打開該文件,對應一塊硬盤空間,並返回一個文件對象賦值給一個變量 res
print(res.read()) 調用文件對象下的讀/寫方法,會被操作系統轉換為讀/寫硬盤的操作
res.close() 向操作系統發起關閉文件的請求,回收系統資源
打開一個文件包含兩部分資源:
應用程序的變量res和操作系統打開的文件。在操作完畢一個文件時,必須把與該文件的這兩部分資源全部回收,回收方法為:
1、res.close() #回收操作系統打開的文件資源
2、del res #回收應用程序級的變量
其中 del res一定要發生在res.close()之后,否則就會導致操作系統打開的文件無法關閉,白白占用資源。
而python自動的垃圾回收機制決定了我們無需考慮del res,這就要求我們,在操作完畢文件后,一定要記住res.close(),但是大多數人還是會不由自主的忘記res.close,考慮到這一點,python提供了關鍵字with
1、在執行完子代碼塊后,with 會自動執行f.close()
with open('a.txt','w') as res:
pass
其中,pass只是為了補全語法結構,沒有實際意義。
2、可用用with同時打開多個文件,用逗號分隔開即可
with open('a.txt','r') as read_res,open('b.txt','w') as write_res:
data = read_res.read()
write_res.write(data)
指定操作文本文件的字符編碼
f = open(...)是由操作系統打開文件,如果打開的是文本文件,會涉及到字符編碼問題,如果沒有為open指定編碼,那么打開文本文件的默認編碼很明顯是操作系統說了算了,操作系統會用自己的默認編碼去打開文件,在windows下是gbk,在linux下是utf-8。
這就用到了上節課講的字符編碼的知識:若要保證不亂碼,文件以什么方式存的,就要以什么方式打開。
f = open('a.txt','r',encoding='utf-8')
控制文件讀寫操作的模式
只需要記住3個①. 'r'(默認的):只讀 ②.'w':只寫 ③.'a':只追加寫
r 只讀模式(只能看不能改)
# 路徑不存在:直接報錯
with open(r'b.txt', 'r', encoding='utf8') as f:
pass
# 路徑存在
with open(r'a.txt', 'r', encoding='utf8') as f:
print(f.read()) # 讀取文件內所有的內容
f.write('123') # 寫文件內容
w 只寫模式(只能寫不能看)
# 路徑不存在:自動創建
# with open(r'b.txt', 'w', encoding='utf8') as f:
# pass
# 路徑存在:1.會先清空文件內容 2.再執行寫入操作
with open(r'a.txt', 'w', encoding='utf8') as f:
# f.read()
f.write('hello world!\n')
f.write('hello world!\n')
f.write('hello world!\n')
運行之前
運行
運行之后直接被清空重新寫入hello world!
a 只追加模式(追加內容)
#路徑不存在:自動創建
# a模式 只追加模式
with open(r'a.txt','a',encoding='utf8') as f:
pass
路徑存在:不會清空文件 在文件末尾添加內容
with open(r'a.txt', 'a', encoding='utf8') as f:
f.write('\n今天周四了 馬上又要放假了 好開心!')
運行五次之后
小總結
我們所使用的r w a讀寫模式都只能操作文本文件
文件操作方法
# 文件操作方法
# 1.讀系列
with open(r'a.txt', 'r', encoding='utf8') as f:
# print(f.read()) # 一次性讀取文件內所有的內容
# print(f.readline()) # 每次只讀文件一行內容
# print(f.readlines()) # 讀取文件所有的內容 組織成列表 每個元素是文件的每行內容
# print(f.readable()) # 判斷當前文件是否具備讀的能力
# 2.寫系列
with open(r'a.txt','w',encoding='utf8') as f:
# f.write('克服一切困難 奧利給!') # 往文件內寫入文本內容
# f.write(123) # 寫入的內容必須是字符串類型
# f.writelines(['jason','kevin','tony']) # 可以將列表中多個字符串元素全部寫入
# print(f.writable()) # True
# print(f.readable()) # False
f.flush() # 直接將內存內文件數據刷到硬盤 相當於ctrl+s
文件優化操作
with open(r'a.txt', 'r', encoding='utf8') as f:
# print(f.read()) # 一次性讀取文件內所有的內容
# print(f.read()) # 一次性讀取文件內所有的內容
# print(f.read()) # 一次性讀取文件內所有的內容
"""
1.一次性讀完之后 光標停留在了文件末尾 無法再次讀取內容
2.該方法在讀取大文件的時候 可能會造成內存溢出的情況
解決上述問題的策略就是逐行讀取文件內容
"""
# for line in f: # 文件變量名f支持for循環 相當於一行行讀取文件內容
# line
'''以后涉及到多行文件內容的情況一般都是采用for循環讀取'''
簡易版本的拷貝功能
1.獲取待拷貝的目標文件路徑
2.獲取即將拷貝到哪個地方的新路徑
3.利用文件操作實現數據拷貝
**1.待拷貝的文件路徑**
wait_copy_file = input('file path>>>:').strip()
**2.新的文件路徑**
new_file_path = input('new path>>>:').strip()
**3.以r模式打開步驟1的路徑 以w模式打開步驟2的路徑**
with open(r'%s' % wait_copy_file, 'rb') as f1, \
open(r'%s' % new_file_path, 'wb') as f2:
for line in f1:
f2.write(line)
二進制模式讀寫操作
with open(r'a.txt','rb') as f:
# print(f.read())
print(f.read(6).decode('utf8')) #b模式下表示字節個數
with open(r'a.txt','r',encoding='utf8') as f:
print(f.read())
print(f.read(4)) 默認的t模式下表示字符個數
"""
read() 括號內可以放數字
在t模式下表示字符個數
在b模式下表示字節個數
英文字符統一使用一個bytes來表示
中文字符統一使用三個bytes來表示
"""
# with open(r'b.txt', 'rb') as f:
# print(f.read(4).decode('utf8'))
# print(f.tell())
# 查看光標移動了多少個字節
# f.seek(3, 1)
# print(f.read().decode('utf8'))
"""
控制文件內光標的移動 f.seek()
f.seek(offset,whence)
offset表示位移量
始終是以字節為最小單位
正數從左往右移動
負數從右往左移動
whence表示模式
0:以文件開頭為參考系(支持tb兩種模式)
1:只支持b模式 以當前位置為參考系
2:只支持b模式 以文件末尾為參考系
"""
# with open(r'b.txt', 'rb') as f:
# print(f.read(4).decode('utf8'))
# print(f.tell()) # 查看光標移動了多少個字節
# f.seek(3, 1)
# print(f.read().decode('utf8'))
"""
控制文件內光標的移動 f.seek()
f.seek(offset,whence)
offset表示位移量
始終是以字節為最小單位
正數從左往右移動
負數從右往左移動
whence表示模式
0:以文件開頭為參考系(支持tb兩種模式)
1:只支持b模式 以當前位置為參考系
2:只支持b模式 以文件末尾為參考系
"""
小練習:實現動態查看最新一條日志的效果
import time
with open('a.txt', 'rb') as f:
f.seek(0, 2)
while True:
line = f.readline()
if len(line) == 0:
# 沒有內容
time.sleep(0.5)
else:
print(line.decode('utf-8'), end='')
import time
with open('a.txt', 'rb') as f:
f.seek(0, 2)
while True:
line = f.readline()
if len(line) == 0:
# 沒有內容
time.sleep(0.5)
else:
print(line.decode('utf-8'), end='')
文件的內容修改
# 第一種方法(廢內存)
with open('a.txt', 'r', encoding='utf8') as f: # 打開一個文本文件a.txt選擇只讀模式
res = f.read() # 將讀出來的文件賦值給res,讀取到內存空間。
data = res.replace('lin', 'xxx') # 然后再把res里面的內容修改后交給變量名data
with open('a.txt', 'w', encoding='utf8') as f1: # 再將a.txt文件內容清空,重新寫入data里的內容~
f1.write(data)
# 這種方法如果要修改的文本文件大的話,對內存占用大。
# 第二種方法 導入標准庫os,遍歷寫入(節省內存,損耗硬盤)
import os # 導入標准庫os
# 然后打開要修改的a.txt選擇只讀賦值給f,打開並創建一個a.txt.swap的文件(可以理解為虛擬文件),賦值給f1
with open('a.txt', 'r', encoding='utf8') as f, \
open('.a.txt.swap', 'w', encoding='utf8') as f1:
for line in f: # 遍歷獲取a.txt每一行內容
f1.write(line.replace('lin', 'xxx')) # 將其中關於lin的內容修改為xxx
os.remove('a.txt') # 隨后先刪除掉舊得a.txt 並將創建的.a.txt.swap文件名改為 a.txt
os.rename('.a.txt.swap', 'a.txt')
兩種方法視情況使用,如果文件過大使用第二種方法,反之,使用第一種更方便~