Python_學習之文件讀寫

Python_學習之文件操做
1、初識⽂文件操做
2、讀寫操做
3、文件的操做順序
4、模式介紹
5、示例html

  1. 文件修改
  2. 大文件進行摘要md5驗證
  3. 批量生成n行數數據的多個文件
  4. 批量讀取文件n行數據
  5. 同時打開多個文件寫法

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")
  1. 大文件進行摘要md5驗證

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()
  1. 批量生成n行數數據的多個文件
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)
  1. 批量讀取文件n行數據
# 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", ])
  1. 同時打開多個文件寫法
"""
考慮以下的案例:
同時打開三個文件,文件行數同樣,要求實現每一個文件依次讀取一行,而後輸出,咱們先來看比較容易想到的寫法:
"""

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)
相關文章
相關標籤/搜索