Python_學習之文件操做
1、初識⽂文件操做
2、讀寫操做
3、文件的操做順序
4、模式介紹
5、示例html
1、初識⽂文件操做
python來讀寫文件是用open()函數來打開一個⽂文件, 獲取到⽂文件句句柄. 而後經過文件句柄就能夠進行各類各樣的操做了. 根據打開方式的不一樣可以執行的操 做也會有相應的差別. python
打開文件的方式: r, w, a, r+, w+, a+, rb, wb, ab, r+b, w+b, a+b默認使⽤用的是r(只讀)模式數據庫
絕對路勁:從根目錄到當前位置如:c:\install\file.txt
相對路勁:同一個文件夾的文件相對於當前程序所在的文件夾而言 ..\表示當前位置的上級目錄 (經常使用)緩存
print(__file__) 獲取當前文件的路徑
2、讀寫操做
默認讀模式只能讀文件,不能作寫操做,寫模式只能寫文件,不能讀文件,除非使用(+)加模式app
3、文件的操做順序
一、找到文件,打開做業,指定模式,根據文件保存時的編碼來指定編碼格式 :open(「path\file」 , moth = 「r/w/r+等」, encoding = 「以什麼編碼格式顯示文件內容」)ide
二、根據對應模式所擁有的方法操做文件: f.read()等其它操做函數
三、關閉文件 :f.close()學習
4、模式介紹
一、只讀(r,rb)優化
r 表示以字符來讀取編碼
rb 表示以字節bytes來讀取 ,如中文gbk 讀取出來的格式爲:b'\xd6\xd0',在讀取圖片,聲音,視頻文件時以此格式。
不管rb仍是wb,ab模式都不用指定encoding,由於文件存儲最後都是字節的形式存起來的,若是指定將報錯: # ValueError: binary mode doesn't take an encoding argument # 找到文件,指向一個變量即句柄 f = open("path\file.txt", mode = "r", encoding = "UTF-8") content = f.read() print(content) f.close() 注:文件都有一個指針,讀模式是從開頭即指針爲0時,進行讀取的,當讀取完畢後,指針停在文件的末尾,若是後面沒有內容,不關閉文件的狀況下,繼續讀取將讀取的時空白。 f.read() 一次性讀取文件的所有內容,若是文件過大,將致使內存崩潰,系統宕機 f.read(n) 能夠指定讀取文件的範圍,若是模式爲r ,n表示幾個字符,若是模式時rb,n表示幾個字節(此處涉及到編碼級,utf-8 中文表示3個字節,gbk 中文表示2個字節) f.readline() 一次讀取一行數據,readline() 默認末尾都加了\n 換行,若是想文件好看,須要在後面加上strip() 去掉換行符 f.readlines() 把每一行一次讀取出來放到一個列表中,而後須要對文件操做能夠for循環,但一樣文件過大時,會致使內存溢出,慎用。 f.readable() 判斷當前模式是否可讀 f.writeable() 判斷當前模式是否可寫 若是須要對文件操做,可直接循環句柄f,它是一行一行拿出來進行操做的。 for line in f: print(f"讀取每一行字符串:{line}")
二、只寫(w, wb)
寫模式,若是文件存在,則清空文件內容,若是文件不存在,則建立新文件,都是從開頭寫,寫完指針停留在最後,直到關閉文件。 f.write("內容") 內容只能是字符串,若是想將列表的元素寫入只能經過for循環列表,直接填入列表,將報錯。 f.flush() 寫完內容記得要及時將內容從緩存寫入磁盤,否則可能致使內容沒有寫入文件 f.close()
三、在讀寫的基礎上附加功能
r + 讀寫,指針從零開始先讀後寫,若是先寫的話,因打開文件指針在0處,寫入的內容將從頭覆蓋相應長度的原文件內容(最經常使用) w+ 寫讀,先清空,後從頭寫入文件,因指針在文件尾部,讀取文件爲空白 a 追加模式,不能讀,只能寫,不會清空文件,會在尾部追加內容 a+ 追加讀,不會清空文件,在尾部追加內容,因指針在尾部,讀取文件時一樣空白 總結:在不改變指針位置的狀況下,a、w+、a+ 都沒法讀到內容,由於加完內容後指針都在文件尾部
四、獲取文件的位置即指針,及改變文件的指針
f.tell() 獲取當前文件的位置,也是以字節爲單位 f.seek(n) 指定指針的位置,n是以字節爲單位,若是是gbk,n 須要爲2的倍數,utf-8 ,n 須要爲3的倍數 移動到開頭:f.seek(0) 移動到結尾:f.seek(0,2) 0表示偏移量,2表示結尾,1表示當前位置 在r+模式下. 若是讀取了了內容. 不論讀取內容多少. 光標顯⽰示的是多少. 再寫入 或者操做⽂文件的時候都是在結尾進⾏的操做.
五、截斷
截斷truncate(),只有在有寫的模式下才能截斷 想截斷: 方法一、經過seek(n)移動指針到截斷位置,truncate() 方法二、經過truncate(n)n沒有指定是刪除截斷位置後的全部內容,n指定了就從頭開始到n個字節
六、經過with……as 操做文件
由於經過f = open("path\file.txt", mode = "r", encoding = "UTF-8")很容易忘記關閉文件致使錯位, 故通常用with方式[上下文],它無需咱們手動關閉,在咱們操做完畢後 with open("path\file_name", moth = "w" , encoding= "utf-8") as f: f.write("name") f.flush()
5、示例
1. 文件修改
import os with open("myPwd.txt", "r", encoding="utf-8") as f1, \ open("myPwd_new.txt", "w", encoding="utf-8") as f2: for line in f1: new_data = line.replace("sun", "xiu") # 逐行修改文件內容 f2.write(new_data) # 將修改後的文件寫入到新文件中 os.remove("myPwd.txt.txt") os.rename("myPwd.txt_new.txt", "myPwd.txt.txt")
import hashlib
def check_md5(file_path): with open(file_path, 'rb') as f: md5_obj = hashlib.md5() while 1: b_data = f.read(4096) if b_data: md5_obj.update(b_data) else: return md5_obj.hexdigest()
import os import time import datetime import threading def writ_file(path, file_name): """ 寫入文件 :param path: :param file_name: :return: """ st = "%s,00128980,00248980,00128980,%s" with open(os.path.join(path, f'{file_name}.txt'), 'a', encoding='utf-8') as fp: for i in range(1, 1651): line_text = st % ((str(i).ljust(11, '0')), datetime.datetime.today().replace(microsecond=0)) fp.write(f'{line_text}\n') print(f"線程{threading.get_ident()},寫入數據:{line_text}完成") if __name__ == '__main__': """ # 批量生產2個1650行的文件 """ now = time.time() threads = [] x = 0 base_dir = os.path.dirname(os.path.abspath(__file__)) for i in range(0, 2): t = threading.Thread(target=writ_file, args=(base_dir, x)) t.start() threads.append(t) x += 1 for j in threads: j.join() print(time.time() - now)
# TODO:優化爲一次奪取500行 import traceback from itertools import zip_longest def grouper(iterable, n, fill_value=None): """ 分組讀取文件 :param iterable: :param n: 行數 :param fill_value: 當最後數據不夠組數時的默認值 :return: """ args = [iter(iterable)] * n return zip_longest(*args, fillvalue=fill_value) def get_data(file_path): """ 讀取文件,一次讀取n行,返回生成器 :param file_path: 文件路徑 :return: 返回的是一組數據 """ try: with open(file_path, 'r', encoding='utf-8') as f: for lines in grouper(f, 500, None): print(f"一次數據{len(lines)}條,數據爲:{lines}") lines_data = [] for line in lines: # 當行數不夠分組時,補充爲None ('xxx',None,) if line: line = line.strip('\n') data = line.split(',') """此處省略從每行數據中獲取須要的數據,僅僅是對字符串的處理了""" lines_data.append(tuple(data)) # 清除掉分組爲None的元素 yield list(filter(None, lines_data)) except Exception as ex: print(f'解析文件[file_path]={file_path}發生異常,異常緣由爲:{ex},位置爲:{traceback.format_exc()}') yield 500 def save_data(generator_data): """批量保存數據:如保存數據庫或文件""" count = 1 for line in generator_data: for db in line: string = "&".join(db) with open("test.txt", mode="a", encoding="utf-8") as f: f.write(f"{string}\n") print(f"第{count}筆數據{line}保存成功") count += 1 def _main(file_path: list): for path in file_path: file_data = get_data(path) save_data(file_data) if __name__ == '__main__': _main(["0.txt", ])
""" 考慮以下的案例: 同時打開三個文件,文件行數同樣,要求實現每一個文件依次讀取一行,而後輸出,咱們先來看比較容易想到的寫法: """ def open_more_file(filename1, filename2, filename3): with open(filename1, 'rb') as fp1: with open(filename2, 'rb') as fp2: with open(filename3, 'rb') as fp3: for i in fp1: j = fp2.readline() k = fp3.readline() print(i, j, k) def open_more_file_for_with(filename1, filename2, filename3): with open(filename1, 'rb') as fp1, open(filename2, 'rb') as fp2, open(filename3, 'rb') as fp3: for i in fp1: j = fp2.readline() k = fp3.readline() print(i, j, k) def open_more_file_for_zip(filename1, filename2, filename3): with open(filename1, 'rb') as fp1: with open(filename2, 'rb') as fp2: with open(filename3, 'rb') as fp3: for i, j, k in zip(fp1, fp2, fp3): print(i, j, k) def open_more_file_for_contextlib(filename1, filename2, filename3): """ 語法糖ExitStack的用法https://docs.python.org/3/library/contextlib.html :param filename1: :param filename2: :param filename3: :return: """ from contextlib import ExitStack with ExitStack() as stack: files = [stack.enter_context(open(fname)) for fname in (filename1, filename2, filename3)] for i, j, k in zip(files[0], files[1], files[2]): print(i, j, k)