python基礎五:python實用的幾個文件操作的案例

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文件。這個要怎麼做? 依然是先梳理一下邏輯:

  1. 首先要遍歷所給的目錄
  2. 拿到各個文件的後綴名
  3. 看看後綴名是否是需要修改的後綴名, 如果是就進行重命名操作

有了這個邏輯, 代碼就比較好寫了。

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 然後後面帶着相應的參數即可。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章