1. 寫在前面
今天整理幾個python關於文件操作的幾個案例, 主要包括用python進行文件的讀寫, 獲取文件名, 獲取文件的後綴名和批量修改文件的後綴。這次整理的幾個方法依然都是從使用的角度出發。比如我需要統計某個txt文件中每個單詞的出現次數, 再比如我需要批量的修改文件的後綴等。 以後涉及到python的文件讀寫操作的內容, 會繼續在這篇文章中進行添加。
Ok, let’s go!
2. python進行文件的讀寫
文件的讀寫在python中比較常見, 文件讀取的時候, 首先要判斷文件是否存在, 若文件操作就進行讀取, 否則報錯。
2.1 文件讀操作
文件讀操作可以的函數有read(), 這個是讀取整個文件, 還有readlines()這個是一行行的進行讀取並保存到列表中。 下面直接上代碼:
import os
def read_file(filename):
if os.path.exists(filename) is False:
raise FileNotFoundError('%s not exists' % (filename,))
f = open(filename, encoding='utf-8') # 後面那個是指定編碼 一般平臺默認編碼格式是utf-8
content = f.read()
f.close()
return content
# 另一種寫法
def read_file(filename):
if os.path.exists(filename) is False:
raise FileNotFoundError('%s not exists' % (filename,))
with open(filename, encoding='utf-8') as f:
content = f.read() # 這時候讀完了之後自動關閉
return content
content = read_file('a.txt')
content
##
'Hey, Python\n\nI just love Python so much,\nand want to get the whole Python stack by this 60-days column\nand believe Python !'
下面是按行讀的效果:
"""文件按行讀"""
def read_file_line(filename):
if not os.path.exists(filename):
raise FileNotFoundError('%s not exists' % filename)
with open(filename, encoding='utf-8') as f:
content = f.readlines()
return content
con = read_file_line('a.txt')
con
##
['Hey, Python\n',
'\n',
'I just love Python so much,\n',
'and want to get the whole Python stack by this 60-days column\n',
'and believe Python !']
好了, 基於上面的這個就可以寫一個統計文件裏面所有單詞的出現次數了。 先走一遍這個過程: 我獲取到文件的內容, 然後進行分詞, 分開之後才能統計個數。
# 下面是一個統計單詞個數的例子
from collections import defaultdict
#這裏的defaultdict(function_factory)構建的是一個類似dictionary的對象,
#其中keys的值,自行確定賦值,但是values的類型,是function_factory的類實例,
#而且具有默認值。比如default(int)則創建一個類似dictionary對象,裏面任何的values都是int的實例,
#而且就算是一個不存在的key, d[key] 也有一個默認值,這個默認值是int()的默認值0.
import re
rec = re.compile('\s+') # 匹配一個或者多個空格
dd = defaultdict(int)
with open('a.txt', 'r+') as f:
for line in f:
clean_line = line.strip()
if clean_line:
words = rec.split(clean_line)
for word in words:
dd[word] += 1
dd = sorted(dd.items(), key=lambda x: x[1], reverse=True)
dd
## 結果如下:
[('Python', 4),
('and', 2),
('Hey,', 1),
('I', 1),
('just', 1),
('love', 1),
('so', 1),
('much,', 1),
('want', 1),
('to', 1),
('get', 1),
('the', 1),
('whole', 1),
('stack', 1),
('by', 1),
('this', 1),
('60-days', 1),
('column', 1),
('believe', 1),
('!', 1)]
上面這個案例有時候還是比較實用的。
2.2 文件寫操作
文件寫操作時,需要首先判斷要寫入的文件路徑是否存在。若不存在,通過 mkdir 創建出路徑;否則,直接寫入文件:
def write_to_file(file_path, file_name):
if not os.path.exists(file_path):
os.mkdir(file_path)
whole_path_filename = os.path.join(file_path, file_name)
to_write_content = '''
Hey, Python
I just love Python so much,
and want to get the whole python stack by this 60-days column
and believe!
'''
with open(whole_path_filename, mode='w', encoding='utf-8') as f:
f.write(to_write_content)
3. 獲取文件名及文件的後綴名
有時候我們拿到一個文件名的時候, 名字上帶有路徑, 這時候我們可以用os.path.split
方法實現路徑和文件名的分離。
file_ext = os.path.split('./data/py/test.py')
ipath, ifile = file_ext
print(ipath, ifile)
##
./data/py test.py
os.path
模塊,splitext
能夠優雅地提取文件後綴。
file_extension = os.path.splitext('./data/py/test.py')
file_extension # .py
基於上面的這個操作, 就可以獲取某個目錄下面指定後綴名的文件
# 獲取某個目錄下指定後綴名的文件
def find_file(work_dir, extension='jpg'):
lst = []
for filename in os.listdir(work_dir):
#print(filename)
splits = os.path.splitext(filename)
ext = splits[1] # 拿到擴展名
if ext == '.'+extension:
lst.append(filename)
return lst
r = find_file('E:\Jupyter Notebook\Python', 'ipynb')
print(r)
## 結果
['Day1-Day2.ipynb', 'Day10_python文件操作案例.ipynb', 'Day3-Day4.ipynb', 'Day5-Day6.ipynb', 'Day7-Day8.ipynb', 'Day9_字符串操作與正則.ipynb']
這個還是很實用的, 比如在CNN的一些任務中, 很多圖片都是以.jpg的形式存放到文件夾裏面的, 我們這時候就需要先獲取到所有的.jpg文件, 然後再通過一些方式把圖片轉成矩陣的表示形式, 這樣我們的網絡纔會認識。
下面再整理一個批量修改文件後綴名的例子, 比如我想把某個目錄下所有的.xls轉成.xlsx文件。這個要怎麼做? 依然是先梳理一下邏輯:
- 首先要遍歷所給的目錄
- 拿到各個文件的後綴名
- 看看後綴名是否是需要修改的後綴名, 如果是就進行重命名操作
有了這個邏輯, 代碼就比較好寫了。
def batch_rename(work_dir, old_ext, new_ext):
for filename in os.listdir(work_dir):
# 獲取文件後綴
split_file = os.path.splitext(filename)
file_ext = split_file[1]
if old_ext == file_ext: # 定位需要修改後綴名的文件
newfile = split_file[0] + new_ext # 修改後文件的完整名稱
# 重命名
os.rename(
os.path.join(work_dir, filename),
os.path.join(work_dir, newfile)
)
下面基於這個整理一點新的知識, 就是如果我是想把上面這個寫到.py的文件裏面, 我從命令行裏運行這個.py文件的時候想把上面的三個參數傳進去, 那麼我應該怎麼傳呢?
這時候,就需要用到python的一個模塊叫做argparse
, 這是python用於解析命令行參數和選項的標準模塊, 具體的我目前也不是瞭解太多, 但是我見過的一般用這個東西的時候, 基本分爲三步:
- 創建 ArgumentParser() 對象
- 調用 add_argument() 方法添加參數
- 使用 parse_args() 解析添加的參數
換成代碼的方式就是:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("x", type=int)
parser.add_argument('y', type=int)
args = parser.parse_args()
# 這樣就能通過命令行傳遞過參數x y來, 我們可以通過下面代碼獲取到這兩個參數
x=args.x
y=args.y
print(x,y)
如果想詳細瞭解每個函數裏面具體參數到底是幹啥用的, 去官網https://docs.python.org/2/howto/argparse.html
所以這裏主要是記錄一下這個東西到底咋用, 而放到這裏例子裏面我們就可以這樣寫(test.py):
def batch_rename(work_dir, old_ext, new_ext):
print(new_ext)
for filename in os.listdir(work_dir):
# 獲取文件後綴
split_file = os.path.splitext(filename)
file_ext = split_file[1]
if old_ext == file_ext: # 定位需要修改後綴名的文件
newfile = split_file[0] + new_ext # 修改後文件的完整名稱
# 重命名
os.rename(
os.path.join(work_dir, filename),
os.path.join(work_dir, newfile)
)
print("完成重命名")
print(os.listdir(work_dir))
def main():
# 命令行參數
parser = argparse.ArgumentParser(description='工作目錄文件後綴名修改')
parser.add_argument('work_dir', metavar='WORK_DIR', type=str, nargs=1, help='修改後綴名文件目錄')
parser.add_argument('old_ext', metavar='OLD_EXT', type=str, nargs=1, help='原來的後綴')
parser.add_argument('new_ext', metavar='NEW_EXT', type=str, nargs=1, help='新的後綴')
args = vars(parser.parse_args())
# 從命令行參數中依次解析出參數
work_dir = args['work_dir'][0]
old_ext = args['old_ext'][0]
if old_ext[0] != '.':
old_ext = '.' + old_ext
new_ext = args['new_ext'][0]
if new_ext[0] != '.':
new_ext = '.' + new_ext
batch_rename(work_dir, old_ext, new_ext)
if __name__ == '__main__':
main()
那麼我們應該怎麼用呢? 打開命令行, 輸入:
python test.py E:\test xls xlsx # 後面三個參數分別就是目錄, 舊後綴名, 新後綴名
這代碼就不解釋了。
爲什麼非要介紹一下argparse
這個庫呢? 當然, 如果是用jupyter notebook這樣的工具寫點小的python demon 或者用keras啥的搭建些神經網絡什麼的, 一般是用不着這個東西的。 但是如果是放在項目的角度, 我們一般是習慣把整個任務拆成很多小塊, 然後每個塊寫一個.py文件, 這樣組織成一個大的工程。 比如訓練一個複雜的神經網絡做一個時序預測, 這時候如果用jupyter的話, 寫出來的代碼會非常的長, 並且不易讀和維護, 這時候就可以考慮分成四塊, 數據集的構造, 模型的建立, 模型的訓練和模型的預測。 每一塊寫到一個.py文件裏面。 這樣代碼的維護和讀起來就比較簡單了, 所以比較大的項目一般是分成很多個.py的。
那講了這麼一大堆, 和argparse
有啥關係呢? 這個就比較適合於我通過命令行運行train.py這樣的代碼訓練神經網絡的時候傳一些必要的參數過去, 比如batch_size, epoch, lr, 輸入輸出的維度等等吧。 你可能又會說爲啥不直接聲明一些變量先存好這些參數呢, 這樣的話即使用命令行直接python train.py不就完事? 當然這個方法可以, 但是如果想頻繁的改變參數,且是在Linux的黑窗口下, 光反覆的打開關閉.py文件其實是挺麻煩的, 不如留一個傳參的接口, 所以這時候可能會用到這個庫。 就比如下面的這個代碼的開頭(train.py):
這時候,我們就可以直接在命令行python train.py
然後後面帶着相應的參數即可。