Python文件操作:高效處理文件的技巧
文件操作是日常工作中不可或缺的一部分。無論是讀取、寫入、拷貝還是移動文件,都需要高效的文件操作技巧。本文將帶領讀者深入探索文件操作的世界,并分享實用的技巧和工具。通過掌握這些技能,您將能夠更加輕松地管理和處理文件,提高工作效率和數(shù)據(jù)處理能力。
一、文件讀寫操作
在學習文件操作之前,先來回顧一下編碼的相關以及數(shù)據(jù)類型的知識。
- 字符串類型(str),在程序中用于表示文字信息,本質(zhì)上是unicode編碼中的二進制。
name = "lisa"
- 字節(jié)類型(bytes),可表示文字信息,本質(zhì)上是utf-8/gbk等編碼的二進制(對unicode進行壓縮,方便文件存儲和網(wǎng)絡傳輸。)
name = "lisa"
data = name.encode('utf-8')
print(data) # b'\xe6\xad\xa6\xe6\xb2\x9b\xe9\xbd\x90'
result = data.decode('utf-8')
print(result) # "lisa"
可表示原始二進制(圖片、文件等信息)
1. 讀文件
讀文本文件:
# 1.打開文件
file_object = open('info.txt', mode='rb')
# 2.讀取文件內(nèi)容,并賦值給data
data = file_object.read()
# 3.關閉文件
file_object.close()
print(data) # b'jack-123\n\xe6\xad\xa6\xe6\xb2\x9b\xe9\xbd\x90-123'
text = data.decode("utf-8")
print(text)
# 1.打開文件
file_object = open('info.txt', mode='rt', encoding='utf-8')
# 2.讀取文件內(nèi)容,并賦值給data
data = file_object.read()
# 3.關閉文件
file_object.close()
print(data) # "lisa"
讀圖片等非文本內(nèi)容文件:
file_object = open('a1.png', mode='rb')
data = file_object.read()
file_object.close()
print(data) # \x91\xf6\xf2\x83\x8aQFfv\x8b7\xcc\xed\xc3}\x7fT\x9d{.3.\xf1{\xe8\...
注意文件路徑操作:
- 相對路徑,你的程序到底在哪里運行的?
- 絕對路徑
# 1.打開文件
file_object = open('/Users/wupeiqi/PycharmProjects/luffyCourse/day09/info.txt', mode='rt', encoding='utf-8')
# 2.讀取文件內(nèi)容,并賦值給data
data = file_object.read()
# 3.關閉文件
file_object.close()
windows系統(tǒng)中寫絕對路徑容易出問題:
# file_object = open('C:\\new\\info.txt', mode='rt', encoding='utf-8')
file_object = open(r'C:\new\info.txt', mode='rt', encoding='utf-8')
data = file_object.read()
file_object.close()
print(data)
讀文件時,文件不存在程序會報錯:
Traceback (most recent call last):
File "/Users/wupeiqi/PycharmProjects/luffyCourse/day09/2.讀文件.py", line 2, in <module>
file_object = open('infower.txt', mode='rt', encoding='utf-8')
FileNotFoundError: [Errno 2] No such file or directory: 'infower.txt'
# 判斷路徑是否存在?
import os
file_path = "/Users/wupeiqi/PycharmProjects/luffyCourse/day09/info.txt"
exists = os.path.exists(file_path)
if exists:
# 1.打開文件
file_object = open('infower.txt', mode='rt', encoding='utf-8')
# 2.讀取文件內(nèi)容,并賦值給data
data = file_object.read()
# 3.關閉文件
file_object.close()
print(data)
else:
print("文件不存在")
2. 寫文件
寫文本文件:
# 1.打開文件
# 路徑:t1.txt
# 模式:wb(要求寫入的內(nèi)容需要是字節(jié)類型)
file_object = open("t1.txt", mode='wb')
# 2.寫入內(nèi)容
file_object.write( "lisa".encode("utf-8") )
# 3.文件關閉
file_object.close()
file_object = open("t1.txt", mode='wt', encoding='utf-8')
file_object.write("lisa")
file_object.close()
寫圖片等文件:
f1 = open('a1.png',mode='rb')
content = f1.read()
f1.close()
f2 = open('a2.png',mode='wb')
f2.write(content)
f2.close()
小案例:利用Python向某個網(wǎng)址發(fā)送請求并獲取結(jié)果(利用第三方的模塊)。
下載第三方模塊:
pip install requests
使用第三方模塊:
import requests
res = requests.get(url="網(wǎng)址")
print(res)
# 案例1:去網(wǎng)上下載一點文本,文本信息寫入文件。
import requests
res = requests.get(
url="https://movie.douban.com/j/search_subjects?type=movie&tag=%E7%83%AD%E9%97%A8&sort=recommend&page_limit=20&page_start=20",
headers={
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36"
}
)
# 網(wǎng)絡傳輸?shù)脑级M制信息(bytes)
# res.content
file_object = open('files/log1.txt', mode='wb')
file_object.write(res.content)
file_object.close()
案例2:去網(wǎng)上下載一張圖片,圖片寫入本地文件。
import requests
res = requests.get(
url="https://hbimg.huabanimg.com/c7e1461e4b15735fbe625c4dc85bd19904d96daf6de9fb-tosv1r_fw1200",
headers={
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36"
}
)
# 網(wǎng)絡傳輸?shù)脑级M制信息(bytes)
# res.content
file_object = open('files/美女.png', mode='wb')
file_object.write(res.content)
file_object.close()
注意事項:
(1)路徑
- 絕對路徑
- 相對路徑
(2)文件不存在時,w模式會新建然后再寫入內(nèi)容;文件存在時,w模式會清空文件再寫入內(nèi)容。
二、文件打開模式
上文我們基于文件操作基本實現(xiàn)了讀、寫的功能,其中涉及的文件操作模式:rt、rb、wt、wb,其實在文件操作中還有其他的很多模式。
========= ===============================================================
Character Meaning
--------- ---------------------------------------------------------------
'r' open for reading (default)
'w' open for writing, truncating the file first
'x' create a new file and open it for writing
'a' open for writing, appending to the end of the file if it exists
'b' binary mode
't' text mode (default)
'+' open a disk file for updating (reading and writing)
The default mode is 'rt' (open for reading text).
關于文件的打開模式常見應用有:
只讀:r,rt,rb
- 存在,讀
- 不存在,報錯
只寫:w,wt,wb
- 存在,清空再寫
- 不存在,創(chuàng)建再寫
只寫:a,at,ab (常用于【尾部追加】)
- 存在,尾部追加。
- 不存在,創(chuàng)建再寫。
三、常見功能
在上述對文件的操作中,我們只使用了write和read來對文件進行讀寫,其實在文件操作中還有很多其他的功能來輔助實現(xiàn)更好的讀寫文件的內(nèi)容。
read,讀
讀所有【常用】:
f = open('info.txt', mode='r',encoding='utf-8')
data = f.read()
f.close()
f = open('info.txt', mode='rb')
data = f.read()
f.close()
- 讀n個字符(字節(jié))【會用到】
f = open('info.txt', mode='r', encoding='utf-8')
# 讀1個字符
data = f.read(1)
f.close()
print(data) # 武
f = open('info.txt', mode='r',encoding='utf-8')
# 讀1個字符
chunk1 = f.read(1)
chunk2 = f.read(2)
print(chunk1,chunk2)
f.close()
f = open('info.txt', mode='rb')
# 讀1個字節(jié)
data = f.read(3)
f.close()
print(data, type(data)) # b'\xe6\xad\xa6' <class 'bytes'>
f = open('info.txt', mode='rb')
# 讀1個字節(jié)
chunk1 = f.read(3)
chunk2 = f.read(3)
chunk3 = f.read(1)
print(chunk1,chunk2,chunk3)
f.close()
readline,讀一行:
f = open('info.txt', mode='r', encoding='utf-8')
v1 = f.readline()
print(v1)
v2 = f.readline()
print(v2)
f.close()
f = open('info.txt', mode='r', encoding='utf-8')
v1 = f.readline()
print(v1)
f.close()
f = open('info.txt', mode='r', encoding='utf-8')
v2 = f.readline()
print(v2)
f.close()
readlines,讀所有行,每行作為列表的一個元素:
f = open('info.txt', mode='rb')
data_list = f.readlines()
f.close()
print(data_list)
循環(huán),讀大文件(readline加強版)【常見】:
f = open('info.txt', mode='r', encoding='utf-8')
for line in f:
print(line.strip())
f.close()
write,寫:
f = open('info.txt', mode='a',encoding='utf-8')
f.write("lisa")
f.close()
f = open('info.txt', mode='ab')
f.write( "lisa".encode("utf-8") )
f.close()
flush,刷到硬盤:
f = open('info.txt', mode='a',encoding='utf-8')
while True:
# 不是寫到了硬盤,而是寫在緩沖區(qū),系統(tǒng)會將緩沖區(qū)的內(nèi)容刷到硬盤。
f.write("lisa")
f.flush()
f.close()
file_object = open('files/account.txt', mode='a')
while True:
user = input("用戶名:")
if user.upper() == "Q":
break
pwd = input("密碼:")
data = "{}-{}\n".format(user, pwd)
file_object.write(data)
file_object.flush()
file_object.close()
移動光標位置(字節(jié)):
f = open('info.txt', mode='r+', encoding='utf-8')
# 移動到指定字節(jié)的位置
f.seek(3)
f.write("lisa")
f.close()
注意:在a模式下,調(diào)用write在文件中寫入內(nèi)容時,永遠只能將內(nèi)容寫入到尾部,不會寫到光標的位置。
獲取當前光標位置:
f = open('info.txt', mode='r', encoding='utf-8')
p1 = f.tell()
print(p1) # 0
f.read(3) # 讀3個字符 3*3=9字節(jié)
p2 = f.tell()
print(p2) # 9
f.close()
f = open('info.txt', mode='rb')
p1 = f.tell()
print(p1) # 0
f.read(3) # 讀3個字節(jié)
p2 = f.tell()
print(p2) # 3
f.close()
四、上下文管理
之前對文件進行操作時,每次都要打開和關閉文件,比較繁瑣且容易忘記關閉文件。以后再進行文件操作時,推薦大家使用with上下文管理,它可以自動實現(xiàn)關閉文件。
with open("xxxx.txt", mode='rb') as file_object:
data = file_object.read()
print(data)
在Python 2.7 后,with又支持同時對多個文件的上下文進行管理,即:
with open("xxxx.txt", mode='rb') as f1, open("xxxx.txt", mode='rb') as f2:
pass
五、文件修改
文件操作改的流程如下所示:
- 以讀的模式打開原文件。
- 以寫的模式創(chuàng)建一個新文件。
- 將原文件的內(nèi)容讀出來修改成新內(nèi)容,寫入新文件。
- 將原文件刪除。
- 將新文件重命名成原文件。
import os
# 1, 以讀的模式打開原文件。
# 2,以寫的模式創(chuàng)建一個新文件。
with open('jack自述',encoding='utf-8') as f1,\
open('jack自述.bak',encoding='utf-8',mode='w') as f2:
# 3,將原文件的內(nèi)容讀出來修改成新內(nèi)容,寫入新文件。
old_content = f1.read()
new_content = old_content.replace('jack', 'SB')
f2.write(new_content)
os.remove('jack自述')
os.rename('jack自述.bak','jack自述')
六、面試題
文件操作,大文件如何讀取內(nèi)容 [ 50G的日志文件 ]:
def read_large_file(file_path, chunk_size=4096):
with open(file_path, 'r') as file:
while True:
data = file.read(chunk_size)
if not data:
break
yield data
# 使用示例
for chunk in read_large_file('large_log_file.log'):
# 處理每個塊的數(shù)據(jù)
process_chunk(chunk)
在Python的文件操作中,readline()和readlines()是用于讀取文件內(nèi)容的兩種常見方法,有什么區(qū)別?
- readline()方法用于每次讀取文件的一行內(nèi)容,并將光標移動到下一行。每次調(diào)用readline(),它會返回文件中的下一行文本作為字符串。如果文件結(jié)束,readline()會返回空字符串。
- readlines()方法則會一次性讀取整個文件的所有行,并將每一行作為一個字符串存儲在一個列表中。該方法返回一個包含所有行的列表。
區(qū)別:
- 返回類型:readline()方法返回一個字符串,即一行的文本內(nèi)容。readlines()方法返回一個列表,其中每個元素是一個字符串,即每行的文本內(nèi)容。
- 讀取方式:readline()方法按行順序逐個讀取,每次調(diào)用讀取一行。而readlines()方法一次讀取整個文件,并將每行作為一個字符串保存在列表中。
- 內(nèi)存占用:readlines()方法將整個文件內(nèi)容存儲在內(nèi)存中的列表中,可能會占用較多的內(nèi)存。而readline()方法只加載一行內(nèi)容,所以對內(nèi)存的占用更加有限。
以下是示例代碼來展示readline()和readlines()的使用:
# 使用readline()方法逐行讀取文件
with open('file.txt', 'r') as file:
line = file.readline()
while line:
print(line)
line = file.readline()
# 使用readlines()方法讀取所有行
with open('file.txt', 'r') as file:
lines = file.readlines()
for line in lines:
print(line)
上述代碼中,假設有一個名為file.txt的文本文件。
- 第一個示例使用readline()方法逐行讀取文件內(nèi)容并打印,直到文件結(jié)束。
- 第二個示例使用readlines()方法一次性讀取整個文件的所有行,并使用for循環(huán)逐行打印。
需要注意的是,在以上示例中,為了演示目的,我們使用with open語句來打開文件,這樣可以自動關閉文件句柄,確保文件操作的正確性和安全性。
七、文件路徑和目錄操作
在python中有一些專門的模塊去操作文件路徑與目錄:
例如os模塊:
1. os
首先導入:
import os
獲取當前腳本絕對路徑:
import os
abs_path = os.path.abspath(__file__)
print(abs_path)
獲取當前文件的上級目錄:
import os
base_path = os.path.dirname( os.path.dirname(路徑) )
print(base_path)
路徑拼接:
import os
p1 = os.path.join(base_path, 'xx')
print(p1)
p2 = os.path.join(base_path, 'xx', 'oo', 'a1.png')
print(p2)
判斷路徑是否存在:
import os
exists = os.path.exists(p1)
print(exists)
-創(chuàng)建文件夾:
import os
os.makedirs(路徑)
path = os.path.join(base_path, 'xx', 'oo', 'uuuu')
if not os.path.exists(path):
os.makedirs(path)
是否是文件夾:
import os
file_path = os.path.join(base_path, 'xx', 'oo', 'uuuu.png')
is_dir = os.path.isdir(file_path)
print(is_dir) # False
folder_path = os.path.join(base_path, 'xx', 'oo', 'uuuu')
is_dir = os.path.isdir(folder_path)
print(is_dir) # True
刪除文件或文件夾:
os.remove("文件路徑")
path = os.path.join(base_path, 'xx')
shutil.rmtree(path)
除了路徑操作之外,再給出一些稍微常見的函數(shù),如下所示:
2. os.listdir
listdir,查看目錄下所有的文件 查看一個目錄下所有的文件【第一層】
使用Python代碼實現(xiàn)遍歷一個文件夾的操作。
import os
def print_directory_contents(sPath):
"""
這個函數(shù)接收文件夾的名稱作為輸入?yún)?shù)
返回該文件夾中文件的路徑
以及其包含文件夾中文件的路徑
"""
for s_child in os.listdir(sPath):
s_child_path = os.path.join(sPath, s_child)
if os.path.isdir(s_child_path):
# 如果是文件夾,走遞歸操作
print_directory_contents(s_child_path)
else:
# 就一定是文件
print(s_child_path)
target_path = 'xxxx'
print_directory_contents(target_path)
使用listdir求文件夾的大小:
import os
lst = [r'D:\code']
size = 0
while lst:
path = lst.pop()
name_lst = os.listdir(path)
for name in name_lst:
full_path = os.path.join(path,name)
if os.path.isdir(full_path):
lst.append(full_path)
elif os.path.isfile(full_path):
size += os.path.getsize(full_path)
print(size)
3. os.walk
Python標準庫os模塊的walk函數(shù)提供了遍歷一個文件夾的功能,它返回一個生成器。walk,查看目錄下所有的文件(含子孫文件)
import os
"""
data = os.listdir("/Users/jack/PycharmProjects/luffyCourse/day14/commons")
print(data)
# ['convert.py', '__init__.py', 'page.py', '__pycache__', 'utils.py', 'tencent']
"""
"""
要遍歷一個文件夾下的所有文件,例如:遍歷文件夾下的所有mp4文件
"""
data = os.walk("/Users/jack/Documents/視頻教程/路飛Python/mp4")
for path, folder_list, file_list in data:
for file_name in file_list:
file_abs_path = os.path.join(path, file_name)
ext = file_abs_path.rsplit(".",1)[-1]
if ext == "mp4":
print(file_abs_path)
使用walk來計算文件夾的總大?。?/p>
import os
g = os.walk('D:\軟件')
s=0
for i in g :
path,dir_list,name_list = i
for j in name_list:
s+=os.path.getsize(os.path.join(path,j))
print(f'該文件夾大小為:{s/1024**2}MB')
八、shutil
shutil庫是Python的一個標準高級文件操作模塊,它與os模塊形成互補的關系。os模塊主要提供了對文件或文件夾的新建、刪除、查看等基本操作,還支持對文件以及目錄的路徑操作。然而,對于復制、移動、刪除、壓縮、解壓等復雜操作,os模塊一般不提供,這時候就需要用到shutil庫了。
shutil庫中包含了一些實用的函數(shù),如copy(), move(), rmtree()等,這些函數(shù)可以幫助我們進行文件和文件夾的復制、移動和刪除等操作。例如,我們可以使用shutil.copy()函數(shù)來復制文件,只需要指定源文件路徑和目標文件路徑即可。此外,shutil庫還提供了一些其他的實用函數(shù),如make_archive()函數(shù),它可以幫助我們將多個文件或文件夾打包成一個歸檔文件。由于對比于os模塊,使用的沒有那么頻繁,所以這里對于shutil的使用稍微簡化,感興趣可以查看官方文檔。
同樣的首先導入:
import shutil
刪除文件夾:
path = os.path.join(base_path, 'xx')
shutil.rmtree(path)
拷貝文件夾:
shutil.copytree("/Users/jack/Desktop/圖/csdn/","/Users/jack/PycharmProjects/CodeRepository/files")
拷貝文件::
shutil.copy("/Users/jack/Desktop/圖/csdn/WX20201123-112406@2x.png","/Users/jack/PycharmProjects/CodeRepository/")
shutil.copy("/Users/jack/Desktop/圖/csdn/WX20201123-112406@2x.png","/Users/jack/PycharmProjects/CodeRepository/x.png")
文件或文件夾重命名:
shutil.move("/Users/jack/PycharmProjects/CodeRepository/x.png","/Users/jack/PycharmProjects/CodeRepository/xxxx.png")
shutil.move("/Users/jack/PycharmProjects/CodeRepository/files","/Users/jack/PycharmProjects/CodeRepository/images")
文件壓縮:
"""
# base_name,壓縮后的壓縮包文件
# format,壓縮的格式,例如:"zip", "tar", "gztar", "bztar", or "xztar".
# root_dir,要壓縮的文件夾路徑
"""
# shutil.make_archive(base_name=r'datafile',format='zip',root_dir=r'files')
解壓文件:
"""
# filename,要解壓的壓縮包文件
# extract_dir,解壓的路徑
# format,壓縮文件格式
"""
# shutil.unpack_archive(filename=r'datafile.zip', extract_dir=r'xxxxxx/xo', format='zip')
九、文件路徑相關
在Python中進行文件操作時,路徑同樣非常重要。正確的路徑可以確保程序能夠找到需要讀寫的文件,并且避免覆蓋或刪除錯誤的文件。在使用Python進行文件操作時,可以使用絕對路徑或相對路徑來指定文件的位置。絕對路徑是從根目錄開始的完整路徑,而相對路徑則是相對于當前工作目錄的路徑。因此,在進行文件操作之前,必須先確定文件的路徑,并使用合適的方法打開和關閉文件,以確保數(shù)據(jù)的正確讀寫和安全性。
1. 轉(zhuǎn)義
windows路徑使用的是\,linux路徑使用的是/。
特別的,在windows系統(tǒng)中如果有這樣的一個路徑 D:\nxxx\txxx\x1,程序會報錯。因為在路徑中存在特殊符 \n(換行符)和\t(制表符),Python解釋器無法自動區(qū)分。
所以,在windows中編寫路徑時,一般有兩種方式:
- 加轉(zhuǎn)義符,例如:"D:\\nxxx\\txxx\\x1"
- 路徑前加r,例如:r"D:\\nxxx\\txxx\\x1"
2. 程序當前路徑
項目中如果使用了相對路徑,那么一定要注意當前所在的位置。
例如:在/Users/jack/PycharmProjects/CodeRepository/路徑下編寫 demo.py文件:
with open("a1.txt", mode='w', encoding='utf-8') as f:
f.write("你好呀")
用以下兩種方式去運行:
- 方式1,文件會創(chuàng)建在 /Users/jack/PycharmProjects/CodeRepository/ 目錄下。
cd /Users/jack/PycharmProjects/CodeRepository/
python demo.py
- 方式2,文件會創(chuàng)建在 `/Users/jack`目錄下。
cd /Users/jack
python /Users/jack/PycharmProjects/CodeRepository/demo.py
import os
"""
# 1.獲取當前運行的py腳本所在路徑
abs = os.path.abspath(__file__)
print(abs) # /Users/jack/PycharmProjects/luffyCourse/day09/20.路徑相關.py
path = os.path.dirname(abs)
print(path) # /Users/jack/PycharmProjects/luffyCourse/day09
"""
base_dir = os.path.dirname(os.path.abspath(__file__))
file_path = os.path.join(base_dir, 'files', 'info.txt')
print(file_path)
if os.path.exists(file_path):
file_object = open(file_path, mode='r', encoding='utf-8')
data = file_object.read()
file_object.close()
print(data)
else:
print('文件路徑不存在')
總結(jié)
文件操作是每個開發(fā)者和數(shù)據(jù)處理人員必備的技能。在本文中,我們詳細介紹了文件讀寫、路徑和目錄操作、文件拷貝以及文件批量處理等方面的技巧和工具。通過學習和應用這些技能,您將能夠更加靈活地處理和管理文件,提高工作效率。要記住,好的文件操作習慣對于數(shù)據(jù)處理和項目管理至關重要。繼續(xù)探索并不斷實踐,您將成為一個更加優(yōu)秀的文件操作專家!