1. 程式人生 > >Python3簡明教程(九)—— 文件處理

Python3簡明教程(九)—— 文件處理

數量 文件大小 工作 enter clas 結束 列表 right des

文件是保存在計算機存儲設備上的一些信息或數據。你已經知道了一些不同的文件類型,比如你的音樂文件,視頻文件,文本文件。Linux 有一個思想是“一切皆文件”,這在實驗最後的 lscpu 的實現中得到了體現。Python 給了你一些簡單的方式操縱文件。

通常我們把文件分為兩類,文本文件和二進制文件。文本文件是簡單的文本,二進制文件包含了只有計算機可讀的二進制數據。

文件操作

文件打開

我們使用 open() 函數打開文件。它需要兩個參數,第一個參數是文件路徑或文件名,第二個是文件的打開模式。模式通常是下面這樣的:

  • "r",以只讀模式打開,你只能讀取文件但不能編輯/刪除文件的任何內容
  • "w",以寫入模式打開,如果文件存在將會刪除裏面的所有內容,然後打開這個文件進行寫入
  • "a",以追加模式打開,寫入到文件中的任何數據將自動添加到末尾

默認的模式為只讀模式,也就是說如果你不提供任何模式,open() 函數將會以只讀模式打開文件。

假設當前目錄下已有sample.py文檔,然後進入Python3打開這個文檔:

>>> fobj = open("sample.txt")
>>> fobj
<_io.TextIOWrapper name=sample.txt mode=r encoding=UTF-8>

文件關閉

打開文件後我們應該總是關閉文件。我們使用方法 close()完成這個操作。

>>> fobj.close()

始終確保你顯式關閉每個打開的文件,一旦它的工作完成你沒有任何理由保持打開文件。因為程序能打開的文件數量是有上限的。如果你超出了這個限制,沒有任何可靠的方法恢復,因此程序可能會崩潰。

每個打開的文件關聯的數據結構(文件描述符/句柄/文件鎖...)都要消耗一些主存資源。因此如果許多打開的文件沒用了你可以結束大量的內存浪費,並且文件打開時始終存在數據損壞或丟失的可能性。

文件讀取

使用 read() 方法一次性讀取整個文件。

>>> fobj = open("
sample.txt") >>> fobj.read() I love Python\nI love shiyanlou\n >>> fobj.close()

如果你再一次調用 read(),它會返回空字符串因為它已經讀取完整個文件。

read(size) 有一個可選的參數 size,用於指定字符串長度。如果沒有指定 size 或者指定為負數,就會讀取並返回整個文件。當文件大小為當前機器內存兩倍時,就會產生問題。反之,會盡可能按比較大的 size 讀取和返回數據。

readline() 能幫助你每次讀取文件的一行。

>>> fobj = open("sample.txt")
>>> fobj.readline()
I love Python\n
>>> fobj.readline()
I love shiyanlou\n
>>> fobj.close()

使用 readlines() 方法讀取所有行到一個列表中。

>>> fobj = open(sample.txt)
>>> fobj.readlines()
[I love Python\n, I love shiyanlou\n]
>>> fobj.close()

你可以循環遍歷文件對象來讀取文件中的每一行。

>>> fobj = open(sample.txt)
>>> for x in fobj:
...     print(x, end = ‘‘)
... 
I love Python
I love shiyanlou
>>> fobj.close()

讓我們寫一個程序,這個程序接受用戶輸入的字符串作為將要讀取的文件的文件名,並且在屏幕上打印文件內容。

#!/usr/bin/env python3
name = input("Enter the file name: ")
fobj = open(name)
print(fobj.read())
fobj.close()

運行程序:

$ cd /home/shiyanlou
$ chmod +x test.py
$ ./test.py
Enter the file name: sample.txt
I love Python
I love shiyanlou

文件寫入

讓我們通過 write() 方法打開一個文件然後我們隨便寫入一些文本。

>>> fobj = open("ircnicks.txt", w)
>>> fobj.write(powerpork\n)
>>> fobj.write(indrag\n)
>>> fobj.write(mishti\n)
>>> fobj.write(sankarshan)
>>> fobj.close()

現在讀取我們剛剛創建的文件:

>>> fobj = open(ircnicks.txt)
>>> s = fobj.read()
>>> fobj.close()
>>> print(s)
powerpork
indrag
mishti
sankarshan

文件操作示例程序

1、拷貝文件程序

在這個例子裏我們拷貝給定的文本文件到另一個給定的文本文件。

#!/usr/bin/env python3
import sys
if len(sys.argv) < 3:
    print("Wrong parameter")
    print("./copyfile.py file1 file2")
    sys.exit(1)
f1 = open(sys.argv[1])
s = f1.read()
f1.close()
f2 = open(sys.argv[2], w)
f2.write(s)
f2.close()

運行程序:

shiyanlou:~/ $ ./copyfile.py sample.txt sample2.txt                           
shiyanlou:~/ $ ll                                                
總用量 20K
lrwxrwxrwx 1 shiyanlou shiyanlou   10 6月   9  2018 anaconda3 -> /anac
onda3
drwxrwxr-x 2 shiyanlou shiyanlou 4.0K 6月   9  2018 Code
-rwxrwxr-x 1 shiyanlou shiyanlou  239 2月  14 20:05 copyfile.py
drwxr-xr-x 2 shiyanlou shiyanlou 4.0K 6月   9  2018 Desktop
-rw-rw-r-- 1 shiyanlou shiyanlou   31 2月  14 20:06 sample2.txt
-rw-rw-r-- 1 shiyanlou shiyanlou   33 8月   8  2016 sample.txt

你可以看到我們在這裏使用了一個新模塊 syssys.argv包含所有命令行參數。這個程序的功能完全可以使用 shell 的 cp 命令替代:在 cp 後首先輸入被拷貝的文件的文件名,然後輸入新文件名。

sys.argv 的第一個值是命令自身的名字,下面這個程序打印命令行參數。

#!/usr/bin/env python3
import sys
print("First value", sys.argv[0])
print("All values")
for i, x  in enumerate(sys.argv):
    print(i, x)

運行程序:

$ ./argvtest.py Hi there
First value ./argvtest.py
All values
0 ./argvtest.py
1 Hi
2 there

這裏我們用到了一個新函數 enumerate(iterableobject),在序列中循環時,索引位置和對應值可以使用它同時得到。

2、文本文件相關信息統計

讓我們試著編寫一個程序,對任意給定文本文件中的制表符、行、空格進行計數。

#!/usr/bin/env python3

import os
import sys


def parse_file(path):
    """
    分析給定文本文件,返回其空格、制表符、行的相關信息

    :arg path: 要分析的文本文件的路徑

    :return: 包含空格數、制表符數、行數的元組
    """
    fd = open(path)
    i = 0
    spaces = 0
    tabs = 0
    for i,line in enumerate(fd):
        spaces += line.count( )
        tabs += line.count(\t)
    # 現在關閉打開的文件
    fd.close()

    # 以元組形式返回結果
    return spaces, tabs, i + 1

def main(path):
    """
    函數用於打印文件分析結果

    :arg path: 要分析的文本文件的路徑
    :return: 若文件存在則為 True,否則 False
    """
    if os.path.exists(path):
        spaces, tabs, lines = parse_file(path)
        print("Spaces {}. tabs {}. lines {}".format(spaces, tabs, lines))
        return True
    else:
        return False


if __name__ == __main__:
    if len(sys.argv) > 1:
        main(sys.argv[1])
    else:
        sys.exit(-1)
    sys.exit(0)

你可以看到程序有兩個函數,main()parse_file()parse_file 函數真正的分析文件並返回結果,然後在 main() 函數裏打印結果。

通過分割代碼到一些更小的單元(函數)裏,能幫助我們組織代碼庫並且也更容易為函數編寫測試用例。

使用with語句

在實際情況中,我們應該嘗試使用 with 語句處理文件對象,它會在文件用完後會自動關閉,就算發生異常也沒關系。它是 try-finally 塊的簡寫:

>>> with open(sample.txt) as fobj:
...     for line in fobj:
...         print(line, end = ‘‘)
... 
I love Python
I love shiyanlou

綜合示例——實現lscpu命令

在 Linux 下你可以使用 lscpu 命令來查看當前電腦的 CPU 相關信息,如下圖:

技術分享圖片

實際上 lscpu 命令是讀取 /proc/cpuinfo 這個文件的信息並美化輸出,現在你可以自己寫一個 Python 程序以只讀模式讀取 /proc/cpuinfo 這個文件,然後打印出來,這樣你就有自己的一個 Python 版本的 lscpu 命令了 :)

記得一行一行的讀取文本文件,不要一次性讀取整個文件,因為有時候你讀取的文件可能比可用內存還大。

參考鏈接:https://www.shiyanlou.com/courses/596

Python3簡明教程(九)—— 文件處理