0 前言
最近一直在與數據集的讀取和處理打交道,不可避免的會用到python中文件處理的知識點,有些函數和知識點雖然知道是怎麼回事,但是感覺掌握的還不是很牢靠,因此打算整理一下知識點,方便以後自己查看。
1 os模塊
在os模塊下有很多文件處理的指定,比如文件的讀取和寫入等命令,下面就簡單介紹幾個常見的命令。
(1) 打開文件
# open()函數簽名
open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
- file表示你要打開的文件地址,文件地址有相對路徑和絕對路徑之分,在open函數中你都可以使用。
- mode表示你要對文件進行怎樣的操作。常見的有下面幾種方式:
'r'表示僅讀取文件內容,如果你向文件中寫入數據的話,會報錯 'io.UnsupportedOperation: not writable'
'w'表示先清空文件內容,然後再寫入數據
'a'表示在原文的末尾追加數據
模式'w+'和'w+b'表示將打開文件並清空文件內容。模式'r+'與'r+b'表示打開文件內容但是並不清空內容,這表示你可以對文件內容進行更新,可以寫入或者更改內容,並不會報錯。模式'a+'與'a+b'表示打開文件讓後在後面追加內容。
-
encoding表示你採用什麼樣的編碼格式。如果讀取或者寫入的是中文字符,可以設置成'utf-8'的編碼格式。
(2) 讀取文件
打開文件之後,我們可以使用一下三種方法讀取文件的內容
-
read()函數:函數的返回值是一個字符串,因此你可以配合字符串函數進行讀取並處理。
with open('./test.txt') as f:
content = f.read()
# 可以配合split()函數將內容進行分割
content1 = f.read().split('/n')
- readlines()函數:函數的返回值是一個列表,列表的每個元素是原文件每一行的數據。
with open('./test.txt') as f:
lines = f.readlines()
# 可以循環索引列表中的內容,並進行打印
lies = [int(i) for i in lines]
- readline()函數:每次值讀取一行數據內容,可以配合循環函數使用,這個佔用內存比較小,因此可以應用在讀取內容比較多的文件。
with open('./test.txt') as f:
while True:
line = f.readline()
if len(line):
print(line)
# 讀取結束
else:
break
(3) 寫入數據
write()函數可以向文件中寫入字符串數據(注意一定是字符串數據)
with open('./test.txt') as f:
# 向文件中寫入數據
f.write('hello world')
(4) 獲取某個路徑下所有的文件地址和文件夾地址
在處理數據集的時候,我需要獲得訓練集下所有xml文件的地址,對其進行讀取。因此可以使用一下幾種方法:
-
os.walk()函數
# 函數簽名
os.walk(top, topdown=True, onerror=None, followlinks=False)
os.walk()函數可以獲得某個路徑下所有的文件和文件夾地址,下面通過一個案例來說明:
# step1: '../data'文件的目錄是這樣的
---- data
---- obj
---- image1.jpg
---- image1.xml
---- obj.data
---- obj.names
# step2: 遍歷文件夾,然後打印
for root_path, sub_dir_path, files_path in os.walk('../data'):
# (1)打印root_path:結果是'../data'和'../data/obj'
print(root_path)
# (2) 打印sub_dir_path: 結果是['obj']和[]
print(sub_dir_path)
# (3)遍歷files_path列表中所有xml文件: 打印結果['image1.xml']
for file_path in files_path:
if file_path.endswith('xml'):
print(file_path)
root_path表示要遍歷的文件夾地址,在案例中是'../data'和'./data/obj'。因爲該文件夾下仍然存在文件夾,所以依然會對子文件夾進行遍歷。
sub_dir_path表示當前文件夾下的子文件夾名稱,如果子文件夾中還存在文件,依然循環打印其子文件名稱。
files_path表示當前文件夾下文件的名稱,如果子文件夾中存在文件,依然將其子文件中的子文件放在列表中進行打印。
- os.listdir()函數
os.listdir()函數可以獲得某個文件夾下所有文件和文件夾的名稱(不是地址)
for path in os.listdir('../data'):
print(path)
# 輸出結果就是
# obj
# obj.data
# obj.names
(5) 拼接路徑
在使用os.walk()函數的時候,我們可以獲得文件夾的路徑以及文件的名稱,而在數據集中,我們需要保存文件的絕對路徑或者是包含當前根目錄的相對路徑,因此我們就需要對文件地址進行拼接。
在拼接路徑的時候,我們可以使用下面os.path.join()函數,下面說明了使用該函數的注意點(借鑑了這位老哥的博客)
os.path.join()函數:連接兩個或更多的路徑名組件
1.如果各組件名首字母不包含’/’,則函數會自動加上
2.如果有一個組件是一個絕對路徑,則在它之前的所有組件均會被捨棄
3.如果最後一個組件爲空,則生成的路徑以一個’/’分隔符結尾
# 案例1:如果各組件名首字母不包含’/’,則函數會自動加上
path1 = 'home'
path2 = 'develop'
path3 = 'code'
print(os.path.join(path1,path2,path3))
# 輸出是:
# home\develop\code
# 案例2:如果有一個組件是一個絕對路徑,則在它之前的所有組件均會被捨棄
# 這一點一定要注意!!!!!
path1 = 'home'
path2 = '/develop'
path3 = 'code'
print(os.path.join(path1,path2,path3))
# 輸出是:
# /develop/code
# 案例3:如果最後一個組件爲空,則生成的路徑以一個’/’分隔符結尾
path1 = '/home'
path2 = 'develop'
path3 = ' '
print(os.path.join(path1,path2,path3))
# 輸出是:
# /home/develop/