­

Python:讀寫文件(I/O) | 組織文件

1. I/O 概述 

   程式與用戶交互涉及到程式的輸入輸出(I/O)

  一種類型是字元串,通過input() print() 函數以及數據類型轉換類函數如(int()),實現數據的輸入輸出。

  另一種類型是讀寫文件,通過文件的創建、讀和寫,實現數據的輸入輸出。

  本文敘述關於讀寫文件與組織文件 

2. 文件與文件路徑

2.1  文件及文件類型

  2.1.1 文件

   文件是一個的序列,可被應用程式翻譯成文本文件和二進位文件。

  是存儲在電腦中的最小單位,位代表設備的某一狀態,但只能是兩種狀態之一(設備開關斷開或合上)。

  文件可分類為文本文件和二進位文件

  2.1.2 文本文件

  文本文件是字元文件,只含有ASCII或Unicode字元,要存儲整數、浮點數或其他數據結構,必須要將它們轉化成對應的字元格式。

  2.1.3 二進位文件

  二進位文件是其他所有文件。諸如字處理文檔、 PDF、 影像、 電子表格和可執行程式。

2.2  文件路徑

   文件以文件夾 (folder)的形式組織起來。文件夾也叫目錄(directory)。

  每個正在運行的程式都有一個 『『當前目錄」作為大多數操作的默認目錄。例如,當你打開一個文件來讀取時,Python 會在當前目錄下尋找這個文件。

  指明一個文件或者目錄的字元串,叫做路徑 (path),比如:‘/Python36/scripts’

  os 模組提供了操作文件和目錄的函數。

  2.2.1 相對路徑

   一個簡單的文件名,如 memo.txt ,同樣被看做是一個路徑,只不過是相對路徑  ,因為它是相對於當前目錄而言的。相對路徑(relative path)就是從當前目錄開始的路徑。

  下面程式碼揭示了 os.path.exists() 的實際

>>> import os 
>>> os.getcwd()  # getcwd() 返回當前工作目錄
'D:\\Python36'
>>> os.chdir('C:\\Windows\\System32')  # chdir() 切換當前目錄
>>> os.getcwd()
'C:\\Windows\\System32'

 

>>> import os
>>> os. path . exists ('(讀寫文件)瘋狂填詞2.txtt ') # 這個文件在電腦上存在,但不存在當前目錄
False
>>> os.path.exists('正則程式碼實踐strip.py') # 這個文件存在當前目錄
True

  2.2.2 絕對路徑

  一個以 開頭的路徑和當前目錄無關,叫做絕對路徑 絕對路徑 (absolute path)就是從文件系統頂部開始的路徑。

    下面程式碼揭示了 os.path.abspath() 的實際效果以及 os.path.relpath() 的用法

>>> import os
>>> os.path.abspath('正則程式碼實踐strip.py')
'D:\\Python36\\正則程式碼實踐strip.py'
>>> import os
>>> os.path.abspath('正則程式碼實踐strip.py')
'D:\\Python36\\正則程式碼實踐strip.py'
>>> os.path.abspath('(讀寫文件)瘋狂填詞2.py') # 這個文件是當前目錄沒有的
'D:\\Python36\\(讀寫文件)瘋狂填詞2.py'
>>> os.path.abspath(r'\Python編程快速上手++讓繁瑣工作自\(讀寫文件)瘋狂填詞2.py') # 這個目錄也是當前目錄不存在的
'D:\\Python編程快速上手++讓繁瑣工作自\\(讀寫文件)瘋狂填詞2.py'
>>> os.path.abspath(r'\Desktop\Python編程快速上手++讓繁瑣工作自動化\(讀寫文件)瘋狂填詞2.py')
'D:\\Desktop\\Python編程快速上手++讓繁瑣工作自動化\\(讀寫文件)瘋狂填詞2.py'
>>> os.path.abspath(r'\Administrator\Desktop\Python編程快速上手++讓繁瑣工作自動化\(讀寫文件)瘋狂填詞2.py')
'D:\\Administrator\\Desktop\\Python編程快速上手++讓繁瑣工作自動化\\(讀寫文件)瘋狂填詞2.py' # 如果沒有指明最頂部根目錄,則該函數返回的目錄的頂部都是當前目錄的頂部,即"D:\\"
>>> os.path.abspath(r'C:\Users\Administrator\Desktop\Python編程快速上手++讓繁瑣工作自動化\(讀寫文件)瘋狂填詞2.py')
'C:\\Users\\Administrator\\Desktop\\Python編程快速上手++讓繁瑣工作自動化\\(讀寫文件)瘋狂填詞2.py'
>>> import os
>>> os.path.relpath('C:\\Windows', 'C:\\')
'Windows'
>>> os.path.relpath('C:\\Windows', 'C:\\spam\\eggs')
'..\\..\\Windows'
>>> os.getcwd()
'D:\\Python36'

  2.2.3 用 os.makedirs() 創建新文件夾(目錄)

  os.makedirs()將創建所有必要的中間文件夾,目的是確保完整路徑名存在。

>>> import os
>>> os.makedirs('D:\\abc\\def\\g')
>>> os.chdir(('D:\\abc\\def\\g')

  2.2.4  用 os.path.join() 構建所有作業系統上都有效的路徑

  這個方法很有用,例如構建文件路徑(創建文件的同時創建路徑)

>>> import os
>>> os.path.join('D:\\Python36', 'test.txt')
'D:\\Python36\\test.txt'

3. 讀寫文件

3.1  用 open() 函數創建或打開文件

  open() 函數返回一個 File 類型對象,將該對象保存於變數中,就可以調用 File 對象的方法

>>> file = open('hello.txt')

  如果當前目錄下沒有 ‘hello.txt’ 文件,則創建該文件並打開。

3.2  read() 或 readlines()方法讀取文件

   open() 函數默認以「讀」模式打開文件,因此不能進行寫入操作,但可以用 read() 方法讀取文件內容(但要實現下面程式碼結果,先要手動打開文件,並敲入對應的內容),

  read() 方法就返回保存在該文件中的字元串。

  readlines() 方法,從文件取得一個字元串的列表。列表中的每個字元串就是文本中的每一行。

>>> helloContent = file.read()
>>> helloContent
'Hello world!'

 

>>> sonnetFile = open('sonnet29.txt')
>>> sonnetFile.readlines()
[When, in disgrace with fortune and men's eyes,\n', ' I all alone beweep my
outcast state,\n', And trouble deaf heaven with my bootless cries,\n', And
look upon myself and curse my fate,']

3.3  write()方法寫入文件

  ‘w’作為第二個參數傳遞給 open(),將以寫模式打開該文件,便可以調用 write() 方法將內容寫入文件。

  ’w’ 模式將會刪除文件原有內容,重新寫入。

  如果不希望刪除原有內容,可以用 ‘a’ 模式將內容以添加的方式寫入文件。

  還有二進位寫入模式 ‘wb’ 等,更多模式請參考Python文檔。

>>> baconFile = open('bacon.txt', 'w')
>>> baconFile.write('Hello world!\n')
13
>>> baconFile.close()
>>> baconFile = open('bacon.txt', 'a')
>>> baconFile.write('Bacon is not a vegetable.')
25
>>> baconFile.close()
>>> baconFile = open('bacon.txt')
>>> content = baconFile.read()
>>> baconFile.close()
>>> print(content)
Hello world!
Bacon is not a vegetable.

  write() 返回值是被寫入字元的個數。文件對象將跟蹤自身的位置,所以下次你調用 write的時候,它會在文件末尾添加新的數據。

3.4 修改文件

  調用 readlines() 方法,利用正則表達匹配修改內容或調用字元串相關方法修改內容,重新寫入新文件。備份原文件,刪除原文件。

3.5  colse() 方法關閉文件

  如果用上下文管理器(with語句)則不需要調用colse()方法,否則應該在最後調用colse()方法。

>>> baconFile = open('bacon.txt', 'w')
>>> baconFile.write('Hello world!\n')
13
>>> baconFile.close()

4. 組織文件

  參考自《Python編程快速上手  讓繁瑣工作自動化》

4.1 查看目錄下所有文件

  調用 os.listdir(path) 將返回傳入函數路徑(path)下所有文件名字元串的列表,包含 path 中的每個文件

>>> os.listdir('C:\\Windows\\System32')
['0409', '12520437.cpx', '12520850.cpx', '5U877.ax', 'aaclient.dll',
......
'xwtpdui.dll', 'xwtpw32.dll', 'zh-CN', 'zh-HK', 'zh-TW', 'zipfldr.dll']

4.2 遍歷目錄樹

  os.walk()在循環的每次迭代中,返回 3 個值:
  1. 當前文件夾名稱的字元串。
  2. 當前文件夾中子文件夾的字元串的列表。
  3. 當前文件夾中文件的字元串的列表。

import os

for folderName, subfolders, filenames in os.walk('C:\\delicious'):
    print('當前目錄(文件夾) folder 是 ' + folderName)
        for subfolder in subfolders:
            print('目錄下子文件夾 subflder 是 ' + folderName + ': ' + subfolder)
        for filename in filenames:
            print('目錄下文件 file 是 ' + folderName + ': '+ filename)
        print('')    

  輸出如下,意思就是os.walk(),先搜索文件夾(根目錄)下的所有子文件夾和文件,而對根目錄下的每個子文件夾又做了同樣的事情,層次迭代,結果就是找到了所有的文件夾與文件(即遍歷了目錄樹)

當前目錄文件夾 folder 是 C:\delicious
目錄下子文件夾 subflder 是 C:\delicious: cats
目錄下子文件夾 subflder 是 C:\delicious: walnut
目錄下文件 file 是 C:\delicious: spam.txt

當前目錄文件夾 folder 是 C:\delicious\cats
目錄下文件 file 是 C:\delicious\cats: catnames.txt
目錄下文件 file 是 C:\delicious\cats: zophie.jpg

當前目錄文件夾 folder 是 C:\delicious\walnut
目錄下子文件夾 subflder 是 C:\delicious\walnut: waffles
當前目錄文件夾 folder 是 C:\delicious\walnut\waffles
目錄下文件 file 是 C:\delicious\walnut\waffles: butter.txt.

4.3 shutil 模組

  4.3.1 複製文件和文件夾

  調用 shutil.copy() 

>>> import shutil, os
>>> os.chdir('C:\\')
>>> shutil.copy('C:\\spam.txt', 'C:\\delicious')
'C:\\delicious\\spam.txt'
>>> shutil.copy('eggs.txt', 'C:\\delicious\\eggs2.txt')
'C:\\delicious\\eggs2.txt'

  4.3.2 文件和文件夾的移動與改名

  調用 shutil.move(source, destination), 下面程式碼:

  1、如果文件夾 C:\eggs 中原來存在一個文件 bacon.txt,它會被C:\\bacon.txt 覆蓋(替換)。

  2、目標文件夾 C:\\eggs 必須存在

  3、 shutil.move() 方法可以實現改文件名

>>> import shutil
>>> shutil.move('C:\\bacon.txt', 'C:\\eggs')
'C:\\eggs\\bacon.txt'
>>> shutil.move('C:\\bacon.txt', 'C:\\eggs\\new_bacon.txt')
'C:\\eggs\\new_bacon.txt'

  4.3.3永久刪除文件和文件夾

  利用 os 模組中的函數,可以刪除一個文件或一個空文件夾。但利用 shutil 模組,可以刪除一個文件夾及其所有的內容。

  • 調用 os.unlink(path)將刪除 path 處的文件。
  • 調用 os.rmdir(path)將刪除 path 處的文件夾。該文件夾必須為空,其中沒有任何文件和文件夾。
  • 調用 shutil.rmtree(path)將刪除 path 處的文件夾,它包含的所有文件和文件夾都會被刪除。

  以上函數都是永久刪除用時要特別小心

import os
    for filename in os.listdir():
        if filename.endswith('.rxt'):
            #os.unlink(filename)
            print(filename)                

  4.3.4 用 send2trash 模組安全地刪除

  send2trash() 函數只能將文件送到垃圾箱, 不能從中恢復文件。

>>> import send2trash
>>> baconFile = open('bacon.txt', 'a') # creates the file
>>> baconFile.write('Bacon is not a vegetable.')
25
>>> baconFile.close()
>>> send2trash.send2trash('bacon.txt')

4.4.zipfile 模組

  4.4.1 讀取 ZIP 文件  

>>> import zipfile, os
>>> os.chdir('C:\\') # move to the folder with example.zip
>>> exampleZip = zipfile.ZipFile('example.zip')
>>> exampleZip.namelist()
['spam.txt', 'cats/', 'cats/catnames.txt', 'cats/zophie.jpg']
>>> spamInfo = exampleZip.getinfo('spam.txt')
>>> spamInfo.file_size
13908
>>> spamInfo.compress_size
3828
>>> 'Compressed file is %sx smaller!' % (round(spamInfo.file_size / spamInfo.compress_size, 2))
'Compressed file is 3.63x smaller!'
>>> exampleZip.close()

  4.4.2 解壓文件 

   運行這段程式碼後, example.zip 的內容將被解壓縮到 C:\

  或者, 你可以向extractall()傳遞的一個文件夾名稱,它將文件解壓縮到那個文件夾, 而不是當前工作目錄。 

>>> import zipfile, os
>>> os.chdir('C:\\') # move to the folder with example.zip
>>> exampleZip = zipfile.ZipFile('example.zip')
>>> exampleZip.extractall()
>>> exampleZip.close()

  4.4.3 創建和添加到 ZIP 文件

  下面程式碼 zipfile.ZipFile()方法中第二個參數 zipfile.ZIP_DEFLATED  是指定了 deflate 壓縮演算法,它對各種類型的數據都很有效

  這段程式碼將創建一個新的 ZIP 文件, 名為 new.zip, 它包含 spam.txt 壓縮後的內容。

  和寫入文件同樣,寫模式將擦除 ZIP 文件中所有原有的內容。如果只是希望將文件添加到原有的 ZIP 文件中, 就要向 zipfile.ZipFile()傳入‘a’作為第二個參數,以添加模式打開 ZIP 文件

>>> import zipfile
>>> newZip = zipfile.ZipFile('new.zip', 'w')
>>> newZip.write('spam.txt', compress_type=zipfile.ZIP_DEFLATED)
>>> newZip.close()