1. 介紹
1.1 介紹
今天福哥帶着大家來學習Python讀寫文件的方法,雖然現階段做項目需要用到文件操作的情況不多了,但是免不了在特殊情況下還是需要用到這個技術的。
今天福哥還會給大家講解Python創建、刪除、授權文件夾的方法,這個技術在控制台程序裡面用途是非常多的。
Python創建、刪除、授權文件夾以及讀寫文件是依靠os庫來實現的,而文件路徑則是通過os的path屬性對象的方法來處理的,我們來逐個介紹一下。
文件夾操作就是目錄操作,在Windows系統裡面文件夾叫folder,翻譯過來就是文件夾,在Linux系統裡面文件夾叫directory,翻譯過來就是目錄。所以創建、刪除、授權文件夾就是創建、刪除、授權目錄。
2. 基本原則
讀寫文件有一些常識需要大家先了解一下。
- 讀寫文件可以是本地電腦上面的文件,也可以是遠程網絡上面的文件,只要授權了就可以操作。
- 文件夾操作可以是本地電腦上面的文件夾,也可以是遠程網絡上面的文件夾,只要授權了就可以操作。
- 要創建文件需要對創建文件的文件夾有寫權限。
- 讀寫已經存在的文件只需要對文件有權限。
- 文件內容分為普通模式和二進制模式,普通模式通過字符串操作,二進制模式通過字節操作。
- 寫文件分為重置寫入和追加寫入,前者會清空已有內容,後者不會。
- 通過文件指針可以精確控制讀寫文件內容的具體位置,但是寫入只會覆蓋已有內容而不會像編輯器一樣插入內容。
- 當前文件夾通過“.”表示,上一級文件夾通過“..”表示。
- 任何文件夾都會有“當前文件夾”和“上一級文件夾”。
3. 文件夾
3.1 遞歸遍歷
遍歷文件夾用到os庫的walk方法,這個方法很方便,直接就把所有的子級、孫級的全部文件夾和文件都遍歷出來了。
rootDir = os.path.dirname(os.path.abspath(__file__)) + "\TFSE"
for root,dirs,files in os.walk(rootDir):
for dir in dirs:
print("文件夾:" + os.path.abspath(root + "\" + dir))
for file in files:
print("文件:" + os.path.abspath(root + "\" + file))1234567
3.2 不遞歸遍歷
os的walk方法很簡單的解決了遍歷文件夾的問題,但是並不是任何情況下我們都需要把文件夾裡面的子級、孫級全部都找出來的,這時候就用到了os的另外一個方法listdir了。
通過os的listdir可以像PHP那樣只遍歷一層目錄下面的內容,可以通過os.path的isdir、isfile方法判斷路徑是文件夾還是文件。
rootDir = os.path.dirname(os.path.abspath(__file__)) + "\TFSE"
files = os.listdir(rootDir)
for fi in files:
fullPath = os.path.abspath(rootDir + "\" + fi)
if os.path.isfile(fullPath):
print("文件:" + fullPath)
elif os.path.isdir(fullPath):
print("文件夾:" + fullPath)123456789
3.3 普通遍歷
既然os的listdir可以遍歷一層目錄,通過遞歸函數也就可以遍歷所有子級、孫級的目錄了。方法和上一課的PHP一樣,封裝一個函數,在函數裡面調用函數自己,實現遞歸。
rootDir = os.path.dirname(os.path.abspath(__file__)) + "\TFSE"
def listFolder(dir):
files = os.listdir(dir)
for fi in files:
fullPath = os.path.abspath(dir + "\" + fi)
if os.path.isfile(fullPath):
print("文件:" + fullPath)
elif os.path.isdir(fullPath):
print("文件夾:" + fullPath)
listFolder(fullPath)
listFolder(rootDir)123456789101112133.4 創建
創建文件夾使用os的mkdir方法,創建之後可以通過os的chmod方法授權,通過os的chown方法設置角色。如果創建失敗(包括文件夾已經存在的情況)則會拋出異常。
需要注意的是os.chmod和os.chown只有在Linux操作系統裡面才能使用。
rootDir = os.path.dirname(os.path.abspath(__file__)) + "\TFSE"
newDir = rootDir + "\newFolder"
os.mkdir(newDir)
os.chmod(newDir, 0755)
os.chown(newDir, 100, -1)1234563.5 刪除
刪除文件夾使用os的rmdir方法。
rootDir = os.path.dirname(os.path.abspath(__file__)) + "\TFSE"
newDir = rootDir + "\newFolder"
os.rmdir(newDir)12343.6 遞歸刪除
如果文件夾含有子級文件/文件夾則需要先刪除子級項目才能刪除文件夾,這個時候就體現出os的walk方法的便捷了。
rootDir = os.path.dirname(os.path.abspath(__file__)) + "\TFSE"
newDir = rootDir + "\newFolder"
for root,dirs,files in os.walk(newDir):
for dir in dirs:
os.rmdir(root + "\" + dir)
for file in files:
os.unlink(root + "\" + file)123456784. 文件
4.1 創建
Python創建文件只有標準方式一種方法,就是通過open、close實現的。
4.1.1 open
使用open創建文件需要了解更多知識,首先我們需要指定“文件打開方式”這個概念,使用open實際上知識打開了一個文件,需要我們指定一個打開文件想要幹什麼的模式,這個就是文件打開方式。
文件打開方式包括:
- r,讀模式
- r+,可讀可寫模式,文件指針在文件開頭
- w,寫模式,重置文件內容
- w+,可讀可寫模式,重置文件內容
- a,寫模式,文件指針在文件末尾
- a+,可讀可寫模式,文件指針在文件末尾
rootDir = os.path.dirname(os.path.abspath(__file__)) + "\TFSE"
newFile = rootDir + "\newFile.py"
fo = open(newFile, "w")
if fo:
writeLen = fo.write("這是福哥新創建的文件")
fo.close()12345674.2 刪除
刪除文件使用os的unlink方法。
rootDir = os.path.dirname(os.path.abspath(__file__)) + "\TFSE"
newFile = rootDir + "\newFile.py"
os.unlink(newFile)12344.3 讀文件
讀文件就是以讀模式或者讀寫模式打開文件。
4.3.1 open
使用open讀文件需要用到while語句通過readline循環讀取。
rootDir = os.path.dirname(os.path.abspath(__file__)) + "\TFSE"
newFile = rootDir + "\newFile.py"
fc = ""
fo = open(newFile, "r")
if fo:
while True:
line = fo.readline()
if not line:
break
fc += line
fo.close()123456789101112
4.4 寫文件
寫文件就是以寫模式或者讀寫模式打開文件。
4.4.1 open
使用open寫文件需要用到write方法。
rootDir = os.path.dirname(os.path.abspath(__file__)) + "\TFSE"
newFile = rootDir + "\newFile.py"
fo = open(newFile, "w")
if fo:
fo.write("福哥說這是全部內容了")
fo.close()
fc = ""
fo = open(newFile, "r")
if fo:
while True:
line = fo.readline()
if not line:
break
fc += line
fo.close()
print(fc)12345678910111213141516171819
4.5 追加寫文件
有時候我們不想將文件內容全部重置了,需要在文件現有內容後面追加內容怎麼辦?
4.5.1 open
將文件打開方式設置為追加寫模式。
rootDir = os.path.dirname(os.path.abspath(__file__)) + "\TFSE"
newFile = rootDir + "\newFile.py"
fo = open(newFile, "a")
if fo:
fo.write("福哥又說話了")
fo.close()
fc = ""
fo = open(newFile, "r")
if fo:
while True:
line = fo.readline()
if not line:
break
fc += line
fo.close()
print(fc)12345678910111213141516171819
4.6 文件指針
我們以可讀可寫模式打開文件後,通過seek移動文件指針,在指定位置進行讀寫操作,這種方式可以避免將文件全部內容加載到內存當中就可以完成很多情況的讀寫操作,可以解決針對超大文件內容的格式化數據的編輯的難題。
4.6.1 文件數據庫
舉例:我們製作一個文件數據庫,將用戶名和密碼存儲到一個文件裡面,用戶名和密碼格式如下
[用戶名(最長50個字符)][密碼(取MD5哈希串,所以固定32個字符)][換行]1然後我們只要保證每一組用戶信息都是一樣的固定長度就可以通過簡單計算知道某一個用戶ID對應的用戶信息在文件的哪個位置上面,進而通過fseek就可以快速定位並讀取用戶信息了。

因為我們規定了文件內的用戶數據格式,那麼通過操控文件指針就可以實現這個文本數據庫的增、刪、改、查功能了,是不是覺得很神奇?
4.6.2 文本數據庫定義
這是文本數據庫TFSimpleTextDb的定義。
class TFSimpleTextDb:
rootDir = ""
fp = ""
fo = None
fs = 0
lastUserId = 0
lastLoginUserId = 0
def __init__(self, rootDir):
self.rootDir = rootDir
self.fp = ""
self.fo = None
self.fs = 0
self.lastUserId = 0
self.lastLoginUserId = 0
def strPad(self, s, padLen, chr):
strLen = len(s)
padLen -= strLen
for i in range(0, padLen):
s += chr
return s
def strRepeat(self, chr, num):
s = ""
for i in range(0, num):
s += chr
return s
def conn(self):
self.fp = self.rootDir + "/users.tongfu.net.txt"
# 數據庫文件不存在就創建它
if not os.path.exists(self.fp):
with open(self.fp, "w") as fo:
fo.close()
try:
# 打開數據庫文件
self.fo = open(self.fp, "r+")
# 記得當前文件尺寸
self.fs = os.path.getsize(self.fp)
return True
except Exception as e:
print(e)
return False
def add(self, user, pwd):
if len(user) > 50:
return false
# 移動文件指針到文件末尾
self.fo.seek(self.fs)
# 寫入一行數據保存用戶名和密碼
# 用戶名用strpad補位,保證數據結構一致
line = "%s%sn" % (
self.strPad(user, 50, ' '),
md5(pwd).hexdigest()
)
self.fo.write(line)
self.fs += len(line)
# 立即寫入新內容到磁盤
self.fo.flush()
# 新用戶ID就是最新一行的行號
self.lastUserId = int(self.fs/(50+32+1))
return True
def mod(self, userId, pwd):
# 移動文件指針到指定userId對應的用戶信息位置
self.fo.seek((50+32+1)*(userId-1))
# 按約定數據長度讀取數據欄位上的數據
userInDb = (self.fo.read(50)).strip()
pwdInDb = self.fo.read(32)
if userInDb == "":
return False
# 修改密碼
# 後退32個字符,在密碼欄位開始處開始寫
self.fo.seek(self.fo.tell()-32)
self.fo.write(md5(pwd).hexdigest())
# 立即寫入新內容到磁盤
self.fo.flush()
return True
def delete(self, userId):
# 移動文件指針到指定userId對應的用戶信息位置
self.fo.seek((50+32+1)*(userId-1))
# 按約定數據長度讀取數據欄位上的數據
userInDb = (self.fo.read(50)).strip()
pwdInDb = self.fo.read(32)
if userInDb == "":
return False
# 修改密碼
# 後退82個字符,在用戶名欄位開始處開始寫
# 寫入82個空字符表示用戶已經被刪除了
self.fo.seek(self.fo.tell()-82)
self.fo.write(self.strRepeat(" ", 82))
# 立即寫入新內容到磁盤
self.fo.flush()
return True
def login(self, user, pwd=""):
fo = open(self.fp, "r")
if fo:
while True:
# 解析出用戶名和密碼
userInDb = fo.read(50)
if not userInDb:
break
pwdInDb = fo.read(32)
if not pwdInDb:
break
LF = fo.read(1)
if not LF:
break
userInDb = userInDb.strip()
# 驗證用戶名
if user == userInDb:
# 驗證密碼
if md5(pwd).hexdigest() == pwdInDb:
# 計算登錄用戶ID
self.lastLoginUserId = int(fo.tell()/(50+32+1))
return 0
else:
return 1 # 密碼錯誤
fo.close()
return 2 # 用戶名不存在
def close(self):
self.fo.close()
def getLastUserId(self):
return self.lastUserId
def getLastLoginUserId(self):
return self.lastLoginUserId1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601614.6.3 文本數據庫測試
下面是對這個TFSimpleTextDb的測試代碼。
myTFSimpleTextDb = TFSimpleTextDb(rootDir)
myTFSimpleTextDb.conn()
if myTFSimpleTextDb.login("福哥") == 2:
print ("創建用戶福哥n")
myTFSimpleTextDb.add("福哥", "123456")
print (myTFSimpleTextDb.getLastUserId())
if myTFSimpleTextDb.login("鬼谷子叔叔") == 2:
print ("創建用戶鬼谷子叔叔n")
myTFSimpleTextDb.add("鬼谷子叔叔", "abcdef")
print (myTFSimpleTextDb.getLastUserId())
if myTFSimpleTextDb.login("同福大哥") == 2:
print ("創建用戶同福大哥n")
myTFSimpleTextDb.add("同福大哥", "123456")
print (myTFSimpleTextDb.getLastUserId())
print ("修改鬼谷子叔叔的密碼n")
print (myTFSimpleTextDb.mod(2, "123456"))
print ("使用新密碼登錄鬼谷子叔叔n")
print (myTFSimpleTextDb.login("鬼谷子叔叔", "123456"))
print (myTFSimpleTextDb.getLastLoginUserId())
print ("刪除鬼谷子叔叔n")
print (myTFSimpleTextDb.delete(2))
print ("再次登錄鬼谷子叔叔n")
print (myTFSimpleTextDb.login("鬼谷子叔叔", "123456"))
myTFSimpleTextDb.close()123456789101112131415161718192021222324252627
5. 超大文件讀寫
超大文件讀寫需要避免將文件裡面的內容全部讀出來放到變量里這種行為,因為變量都是存在於內存當中的,如果變量裡面的數據太多會把內存用光,就會導致系統癱瘓,這個太可怕了~~
5. 將一個10G文件里的“福哥”換成“鬼谷子叔叔”
這個時候我們可以通過開啟兩個文件指針,一個文件指針負責讀現有文件,一個文件指針負責寫新的臨時文件,完成後刪除現有文件,再將臨時文件重命名為原來的文件,就搞定了~~
rootDir = os.path.dirname(os.path.abspath(__file__)) + "\TFSE"
newFile = rootDir + "\newFile.py"
tmpFile = rootDir + "\newFile.py.tmp"
foNew = open(newFile, "r")
foTmp = open(tmpFile, "w")
if foNew and foTmp:
while True:
tmpLine = foNew.readline()
if not tmpLine:
break
tmpLine = tmpLine.replace("福哥", "鬼谷子叔叔")
foTmp.write(tmpLine)
foNew.close()
foTmp.close()
os.unlink(newFile)
os.rename(tmpFile, newFile)
fc = ""
with open(newFile, "r") as fo:
fc += fo.readline()
print(fc)12345678910111213141516171819202122
6. 總結
好了,今天童鞋們跟着福哥系統地將Python語言操作文件夾、操作文件的方法學習了一遍,有了這些技術之後,今後在項目當中處理各種有關文件夾/文件的問題就不會發怵了!
要注意一點哦,文件夾操作、文件操作屬於IO操作,是有一定風險的,一定不要把文件夾/文件的路徑搞錯了,要不把系統文件或者程序文件寫壞了,系統有可能就完蛋了~~
原創文章,作者:投稿專員,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/274910.html
微信掃一掃
支付寶掃一掃