刻意練習:Python基礎 -- Task07. 文件與文件系統

背景

我們準備利用17天時間,將 “Python基礎的刻意練習” 分爲如下任務:

這是我的 07/12 次任務的打卡內容。我學習 Python 的思路是,先去熟悉 Python 的整體語法框架與自己熟悉的編程語言進行知識點的連接,後面遇到問題再來慢慢補充,慢慢形成自己的知識結構。


Python 基礎語法

1. 打開文件

  • open(file, mode='r') 接收兩個參數:文件名(file)和模式(mode),用於打開一個文件,並返回文件對象,如果該文件無法被打開,會拋出OSError

打開模式 | 執行操作

完整的語法格式爲:

  • open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None)
  • file: 必需,文件路徑(相對或者絕對路徑)。
  • mode: 可選,文件打開模式
  • buffering: 設置緩衝
  • encoding: 一般使用utf8
  • errors: 報錯級別
  • newline: 區分換行符
f = open('將進酒.txt')
print(f)
# <_io.TextIOWrapper name='將進酒.txt' mode='r' encoding='cp936'>

for each in f:
    print(each)

# 君不見,黃河之水天上來,奔流到海不復回。
# 君不見,高堂明鏡悲白髮,朝如青絲暮成雪。
# 人生得意須盡歡,莫使金樽空對月。
# 天生我材必有用,千金散盡還復來。
# 烹羊宰牛且爲樂,會須一飲三百杯。
# 岑夫子,丹丘生,將進酒,杯莫停。
# 與君歌一曲,請君爲我傾耳聽。
# 鐘鼓饌玉不足貴,但願長醉不復醒。
# 古來聖賢皆寂寞,惟有飲者留其名。
# 陳王昔時宴平樂,斗酒十千恣歡謔。
# 主人何爲言少錢,徑須沽取對君酌。
# 五花馬,千金裘,呼兒將出換美酒,與爾同銷萬古愁。

2. 文件對象方法

  • fileObject.close() 用於關閉一個已打開的文件。關閉後的文件不能再進行讀寫操作, 否則會觸發ValueError錯誤。
f = open("將進酒.txt")
print('FileName:', f.name)  # FileName: 將進酒.txt
f.close()
  • fileObject.read([size]) 用於從文件讀取指定的字符數,如果未給定或爲負則讀取所有。
f = open('將進酒.txt', 'r')
line = f.read(20)
print("讀取的字符串: %s" % line)
# 讀取的字符串: 君不見,黃河之水天上來,奔流到海不復回。

f.close()
  • fileObject.readline()讀取整行,包括 “\n” 字符。
f = open('將進酒.txt', 'r')
line = f.readline()
print("讀取的字符串: %s" % line)
# 讀取的字符串: 君不見,黃河之水天上來,奔流到海不復回。
f.close()
  • fileObject.readlines()用於讀取所有行(直到結束符 EOF)並返回列表,該列表可以由 Python 的 for... in ... 結構進行處理。
f = open('將進酒.txt', 'r')
lines = f.readlines()
print(lines)

for each in lines:
    each.strip()
    print(each)

# 君不見,黃河之水天上來,奔流到海不復回。
# 君不見,高堂明鏡悲白髮,朝如青絲暮成雪。
# 人生得意須盡歡,莫使金樽空對月。
# 天生我材必有用,千金散盡還復來。
# 烹羊宰牛且爲樂,會須一飲三百杯。
# 岑夫子,丹丘生,將進酒,杯莫停。
# 與君歌一曲,請君爲我傾耳聽。
# 鐘鼓饌玉不足貴,但願長醉不復醒。
# 古來聖賢皆寂寞,惟有飲者留其名。
# 陳王昔時宴平樂,斗酒十千恣歡謔。
# 主人何爲言少錢,徑須沽取對君酌。
# 五花馬,千金裘,呼兒將出換美酒,與爾同銷萬古愁。

f.close()
  • fileObject.tell()返回文件的當前位置,即文件指針當前位置。
f = open('將進酒.txt', 'r')
line = f.readline()
print(line)
# 君不見,黃河之水天上來,奔流到海不復回。
pos = f.tell()
print(pos)  # 42
f.close()
  • fileObject.seek(offset[, whence])用於移動文件讀取指針到指定位置。
  • offset:開始的偏移量,也就是代表需要移動偏移的字節數,如果是負數表示從倒數第幾位開始。
  • whence:可選,默認值爲 0。給 offset 定義一個參數,表示要從哪個位置開始偏移;0 代表從文件開頭開始算起,1 代表從當前位置開始算起,2 代表從文件末尾算起。
f = open('將進酒.txt', 'r')
line = f.readline()
print(line)
# 君不見,黃河之水天上來,奔流到海不復回。
line = f.readline()
print(line)
# 君不見,高堂明鏡悲白髮,朝如青絲暮成雪。
f.seek(0, 0)
line = f.readline()
print(line)
# 君不見,黃河之水天上來,奔流到海不復回。
f.close()
  • fileObject.write(str)用於向文件中寫入指定字符串,返回的是寫入的字符長度。
f = open('workfile.txt', 'wb+')
print(f.write(b'0123456789abcdef'))  # 16
print(f.seek(5))  # 5
print(f.read(1))  # b'5'
print(f.seek(-3, 2))  # 13
print(f.read(1))  # b'd'

在文件關閉前或緩衝區刷新前,字符串內容存儲在緩衝區中,這時你在文件中是看不到寫入的內容的。

如果文件打開模式帶b,那寫入文件內容時,str(參數)要用encode方法轉爲bytes形式,否則報錯:TypeError: a bytes-like object is required, not 'str'

str = '...'
# 文本 = Unicode字符序列
# 相當於 string 類型

str = b'...'
# 文本 = 八位序列(0到255之間的整數)
# 字節文字總是以‘b’或‘B’作爲前綴;它們產生一個字節類型的實例,而不是str類型。
# 相當於 byte[]

Sample:

f = open('將進酒.txt', 'r+')
str = '\n作者:李白'
f.seek(0, 2)
line = f.write(str)
f.seek(0, 0)
for each in f:
    print(each)

# 君不見,黃河之水天上來,奔流到海不復回。
# 君不見,高堂明鏡悲白髮,朝如青絲暮成雪。
# 人生得意須盡歡,莫使金樽空對月。
# 天生我材必有用,千金散盡還復來。
# 烹羊宰牛且爲樂,會須一飲三百杯。
# 岑夫子,丹丘生,將進酒,杯莫停。
# 與君歌一曲,請君爲我傾耳聽。
# 鐘鼓饌玉不足貴,但願長醉不復醒。
# 古來聖賢皆寂寞,惟有飲者留其名。
# 陳王昔時宴平樂,斗酒十千恣歡謔。
# 主人何爲言少錢,徑須沽取對君酌。
# 五花馬,千金裘,呼兒將出換美酒,與爾同銷萬古愁。
# 作者:李白

f.close()
  • fileObject.writelines(sequence)向文件寫入一個序列字符串列表,如果需要換行則要自己加入每行的換行符\n
f = open('test.txt', 'w+')
seq = ['小馬的程序人生\n', '老馬的程序人生']
f.writelines(seq)
f.seek(0, 0)
for each in f:
    print(each)
    
# 小馬的程序人生
# 老馬的程序人生
f.close()

3. OS 模塊中關於文件/目錄常用的函數使用方法

我們所知道常用的操作系統就有:Windows,Mac OS,Linu,Unix等,這些操作系統底層對於文件系統的訪問工作原理是不一樣的,因此你可能就要針對不同的系統來考慮使用哪些文件系統模塊……,這樣的做法是非常不友好且麻煩的,因爲這樣就意味着當你的程序運行環境一改變,你就要相應的去修改大量的代碼來應對。

有了OS(Operation System)模塊,我們不需要關心什麼操作系統下使用什麼模塊,OS模塊會幫你選擇正確的模塊並調用。

  • os.getcwd()用於返回當前工作目錄。
  • os.chdir(path)用於改變當前工作目錄到指定的路徑。
import os

path = 'C:\\'
print("當前工作目錄 : %s" % os.getcwd())
# 當前工作目錄 : C:\Users\Administrator\PycharmProjects\untitled1
os.chdir(path)
print("目錄修改成功 : %s" % os.getcwd())
# 目錄修改成功 : C:\
  • os.listdir(path)返回path指定的文件夾包含的文件或文件夾的名字的列表。
import os

dirs = os.listdir()
for item in dirs:
    print(item)
  • os.mkdir(path)創建單層目錄,如果該目錄已存在拋出異常。
import os

if os.path.isdir(r'.\b') is False:
    os.mkdir(r'.\B')
    os.mkdir(r'.\B\A')

os.mkdir(r'.\C\A') # FileNotFoundError
  • os.makedirs(path)用於遞歸創建多層目錄,如果該目錄已存在拋出異常。
import os
os.makedirs(r'.\E\A')
  • os.remove(path)用於刪除指定路徑的文件。如果指定的路徑是一個目錄,將拋出 OSError
import os

print("目錄爲: %s" % os.listdir(r'.\E\A'))
os.remove(r'.\E\A\test.txt')
print("目錄爲: %s" % os.listdir(r'.\E\A'))
  • os.rmdir(path)用於刪除單層目錄。僅當這文件夾是空的纔可以, 否則, 拋出 OSError
import os

print("目錄爲: %s" % os.listdir(r'.\E'))
os.rmdir(r'.\E\A')
print("目錄爲: %s" % os.listdir(r'.\E'))
  • os.removedirs(path)遞歸刪除目錄,從子目錄到父目錄逐層嘗試刪除,遇到目錄非空則拋出異常。
import os

print("目錄爲: %s" % os.listdir(os.getcwd()))
os.removedirs(r'.\E\A')  # 先刪除A 然後刪除E
print("目錄爲: %s" % os.listdir(os.getcwd()))
  • os.rename(src, dst)方法用於命名文件或目錄,從 srcdst,如果 dst 是一個存在的目錄, 將拋出 OSError
import os

print("目錄爲: %s" % os.listdir(os.getcwd()))
os.rename("test", "test2")
print("重命名成功。")
print("目錄爲: %s" % os.listdir(os.getcwd()))
  • os.system(command)運行系統的shell命令(將字符串轉化成命令)
import os

path = os.getcwd() + '\\a.py'
a = os.system(r'python %s' % path)

os.system('calc')  # 打開計算器
  • os.curdir指代當前目錄(.
  • os.pardir指代上一級目錄(..
  • os.sep輸出操作系統特定的路徑分隔符(win下爲\\,Linux下爲/
  • os.linesep當前平臺使用的行終止符(win下爲\r\n,Linux下爲\n
  • os.name指代當前使用的操作系統(包括:‘mac’,‘nt’)
import os

print(os.curdir)  # .
print(os.pardir)  # ..
print(os.sep)  # \
print(os.linesep)
print(os.name)  # nt
  • os.path.basename(path)去掉目錄路徑,單獨返回文件名
  • os.path.dirname(path)去掉文件名,單獨返回目錄路徑
  • os.path.join(path1[, path2[, ...]])path1path2 各部分組合成一個路徑名
  • os.path.split(path)分割文件名與路徑,返回(f_path,f_name)元組。如果完全使用目錄,它會將最後一個目錄作爲文件名分離,且不會判斷文件或者目錄是否存在。
  • os.path.splitext(path)分離文件名與擴展名,返回(f_path,f_name)元組。
import os

# 返回文件名
print(os.path.basename(r'C:\test\lsgo.txt'))  # lsgo.txt
# 返回目錄路徑
print(os.path.dirname(r'C:\test\lsgo.txt'))  # C:\test
# 將目錄和文件名合成一個路徑
print(os.path.join('C:\\', 'test', 'lsgo.txt'))  # C:\test\lsgo.txt
# 分割文件名與路徑
print(os.path.split(r'C:\test\lsgo.txt'))  # ('C:\\test', 'lsgo.txt')
# 分離文件名與擴展名
print(os.path.splitext(r'C:\test\lsgo.txt'))  # ('C:\\test\\lsgo', '.txt')
  • os.path.getsize(file)返回指定文件大小,單位是字節。
  • os.path.getatime(file)返回指定文件最近的訪問時間
  • os.path.getctime(file)返回指定文件的創建時間
  • os.path.getmtime(file)返回指定文件的最新的修改時間
  • 浮點型秒數,可用time模塊的gmtime()localtime()函數換算
import os
import time

file = r'.\lsgo.txt'
print(os.path.getsize(file))  # 30
print(os.path.getatime(file))  # 1565593737.347196
print(os.path.getctime(file))  # 1565593737.347196
print(os.path.getmtime(file))  # 1565593797.9298275
print(time.gmtime(os.path.getctime(file)))
# time.struct_time(tm_year=2019, tm_mon=8, tm_mday=12, tm_hour=7, tm_min=8, tm_sec=57, tm_wday=0, tm_yday=224, tm_isdst=0)
print(time.localtime(os.path.getctime(file)))
# time.struct_time(tm_year=2019, tm_mon=8, tm_mday=12, tm_hour=15, tm_min=8, tm_sec=57, tm_wday=0, tm_yday=224, tm_isdst=0)
  • os.path.exists(path)判斷指定路徑(目錄或文件)是否存在
  • os.path.isabs(path)判斷指定路徑是否爲絕對路徑
  • os.path.isdir(path)判斷指定路徑是否存在且是一個目錄
  • os.path.isfile(path)判斷指定路徑是否存在且是一個文件
  • os.path.islink(path)判斷指定路徑是否存在且是一個符號鏈接
  • os.path.ismount(path)判斷指定路徑是否存在且是一個懸掛點
  • os.path.samefile(path1,path2)判斷path1和path2兩個路徑是否指向同一個文件
import os

print(os.path.ismount('D:\\'))  # True
print(os.path.ismount('D:\\Test'))  # False

4. 序列化與反序列化

Python 的 pickle 模塊實現了基本的數據序列和反序列化。

  • 通過 pickle 模塊的序列化操作我們能夠將程序中運行的對象信息保存到文件中去,永久存儲。
  • 通過 pickle 模塊的反序列化操作,我們能夠從文件中創建上一次程序保存的對象。

pickle模塊中最常用的函數爲:

pickle.dump(obj, file, [,protocol])obj對象序列化存入已經打開的file中。

  • obj:想要序列化的obj對象。
  • file:文件名稱。
  • protocol:序列化使用的協議。如果該項省略,則默認爲0。如果爲負值或HIGHEST_PROTOCOL,則使用最高的協議版本。

pickle.load(file)file中的對象序列化讀出。

  • file:文件名稱。
import pickle

dataList = [[1, 1, 'yes'],
            [1, 1, 'yes'],
            [1, 0, 'no'],
            [0, 1, 'no'],
            [0, 1, 'no']]
dataDic = {0: [1, 2, 3, 4],
           1: ('a', 'b'),
           2: {'c': 'yes', 'd': 'no'}}

# 使用dump()將數據序列化到文件中
fw = open(r'.\dataFile.pkl', 'wb')

# Pickle the list using the highest protocol available.
pickle.dump(dataList, fw, -1)

# Pickle dictionary using protocol 0.
pickle.dump(dataDic, fw)
fw.close()

# 使用load()將數據從文件中序列化讀出
fr = open('dataFile.pkl', 'rb')
data1 = pickle.load(fr)
print(data1)
data2 = pickle.load(fr)
print(data2)
fr.close()

# [[1, 1, 'yes'], [1, 1, 'yes'], [1, 0, 'no'], [0, 1, 'no'], [0, 1, 'no']]
# {0: [1, 2, 3, 4], 1: ('a', 'b'), 2: {'c': 'yes', 'd': 'no'}}

總結

好了,到此爲止有關於 文件、文件系統 和 序列化與反序列化 部分就介紹完了,大家要根據上面的例子多多體會,只有刻意練習才能掌握一門技術,沒有捷徑的,加油啊!See You!


參考文獻

  • https://www.runoob.com/python3/python3-tutorial.html
  • https://www.bilibili.com/video/av4050443

相關圖文

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