返回文章列表

Python檔案與程式操作網路程式設計

本文探討 Python 檔案與程式操作,以及網路程式設計的實務技巧。涵蓋使用 subprocess 模組執行外部命令、安全檔案寫入、檔案路徑操作、後設資料操作、shutil 模組的高階檔案操作、tempfile 模組的臨時檔案使用、以及使用 socket

Python 系統管理

Python 提供了強大的檔案、程式與網路操作能力,讓開發者能有效控制系統資源與網路互動。檔案操作包含安全寫入、路徑解析、後設資料讀取等,搭配 shutil 模組更能進行進階檔案管理。程式管理則仰賴 subprocess 模組,執行外部命令、擷取輸出、自訂工作目錄,提升自動化效率。網路程式設計則可運用 socket 模組,建立網路連線、傳送請求、接收回應,實作客製化網路應用。這些技術的整合運用,讓 Python 成為系統管理和網路應用開發的利器。

Jupyter Notebook 與互動式開發環境

Jupyter Notebook 提供了一個根據 Web 的介面來進行互動式開發與資料分析。這個環境結合了多種工具,包括終端模擬器、文字編輯器和 Notebook,讓使用者能夠在瀏覽器中進行幾乎所有的開發和管理工作。

Notebook 的基本組成

Notebook 是 Jupyter 的核心元件,由一系列的儲存格(Cell)組成。最常用的兩種儲存格型別是 CodeMarkdown

  1. Code 儲存格:包含 Python 程式碼片段,可以在 Session 的名稱空間中執行。這些儲存格的執行結果會被保留,並且可以按照任意順序重新執行。

    # 示例程式碼:計算圓的面積
    import math
    radius = 5
    area = math.pi * (radius ** 2)
    print(f"半徑為 {radius} 的圓面積是 {area:.2f}")
    

    內容解密:

    • import math:匯入 Python 的數學函式庫,用於取得 π 的值。
    • radius = 5:設定圓的半徑為 5。
    • area = math.pi * (radius ** 2):使用公式計算圓的面積。
    • print(f"..."):輸出計算結果,使用 f-string 格式化輸出字串。
  2. Markdown 儲存格:支援 Markdown 語法,用於新增說明、標題和格式化的文字,提供檔案式的註解和解釋。

多核心支援與擴充套件性

預設情況下,Jupyter Server 使用本地的 IPython 核心,但支援連線來自不同環境的核心。只需在目標環境中安裝 ipykernel 套件,即可將該環境註冊為可用的核心。

# 在特定環境中安裝 ipykernel 並註冊核心
python -m ipykernel install --name my-special-env --display-name "My Env" --prefix=$DIRECTORY
# 在 Jupyter Server 環境中安裝核心規範
jupyter kernelspec install $DIRECTORY/share/jupyter/kernels/my-special-env --sys-prefix

內容解密:

  • python -m ipykernel install:在指定環境中安裝並註冊 IPython 核心。
  • --name--display-name:分別指定核心的內部名稱和顯示名稱。
  • --prefix=$DIRECTORY:指定安裝路徑。
  • jupyter kernelspec install:將核心規範安裝到 Jupyter Server 環境中。
  • --sys-prefix:將核心安裝在 Jupyter Server 的虛擬環境中。

實用功能與應用場景

  1. 魔法指令:Jupyter 繼承了 IPython 的魔法指令,例如 !pip install ...,可以直接在 Notebook 中安裝套件,讓檔案兼具可讀性和可執行性。

  2. 重啟核心與執行儲存格:可以重啟核心並依序執行所有儲存格,測試整個 Notebook 的正確性和可重複性。

  3. 附件與分享:Notebook 可以匯出為 HTML 或 PDF,方便附加到報告或檔案。許多平台如 GitHub 已支援直接渲染 Notebook。

JupyterLab:遠端開發環境

JupyterLab 提供了一個功能豐富的瀏覽器端開發環境,包括:

  • 檔案管理器:上傳、下載檔案,管理 Notebook 和其他檔案。
  • IPython 控制檯:適合需要頻繁輸入短命令的場景。
  • 檔案編輯器:直接編輯遠端檔案,適合緊急修復程式碼。
  • 瀏覽器終端:提供完整的遠端終端存取能力。
@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle

title Python檔案與程式操作網路程式設計

package "安全架構" {
    package "網路安全" {
        component [防火牆] as firewall
        component [WAF] as waf
        component [DDoS 防護] as ddos
    }

    package "身份認證" {
        component [OAuth 2.0] as oauth
        component [JWT Token] as jwt
        component [MFA] as mfa
    }

    package "資料安全" {
        component [加密傳輸 TLS] as tls
        component [資料加密] as encrypt
        component [金鑰管理] as kms
    }

    package "監控審計" {
        component [日誌收集] as log
        component [威脅偵測] as threat
        component [合規審計] as audit
    }
}

firewall --> waf : 過濾流量
waf --> oauth : 驗證身份
oauth --> jwt : 簽發憑證
jwt --> tls : 加密傳輸
tls --> encrypt : 資料保護
log --> threat : 異常分析
threat --> audit : 報告生成

@enduml

此圖示展示了 JupyterLab 的主要元件及其相互關係。JupyterLab 提供了一個整合的開發環境,各元件之間協同工作,極大地提高了遠端開發和管理的效率。

作業系統自動化:檔案操作與管理

Python 在作業系統自動化方面有著廣泛的應用,尤其是在 Unix-like 系統中。Python 對傳統的 Unix C API 進行了輕量級的封裝,使其在保持強大功能的同時,也具備了一定的安全性。這種方法被稱為「帶有泡沫墊的 C 語言」。Python 的這一特性使其成為 Unix shell 程式和 C 程式語言之間的理想選擇。

檔案操作

在 Unix 系統中,許多事物都被視為檔案,即使它們不是傳統意義上的檔案。Python 程式可以以兩種方式處理檔案內容:以文字模式或二進位模式開啟。

二進位檔案操作

當以二進位模式開啟檔案時,位元組被讀取和寫入為位元組字串。這對於非文字檔案(如圖片檔案)非常有用。

with open("Untitled.xcf", "rb") as fp:
    header = fp.read(100)

在這個例子中,rb 引數代表「讀取,二進位模式」。讀取檔案的前 100 個位元組,這是一種常見的技術,因為許多檔案在其開頭包含元資料。

header[:9].decode('ascii')

前 9 個字元可以解碼為 ASCII 文字,恰好是該檔案格式的名稱。

header[9:9+4].decode('ascii')

接下來的 4 個字元代表版本號。

struct.unpack('>I', header[9+4+1:9+4+1+4])

使用 struct 模組解析接下來的 4 個位元組,它們代表圖片的寬度,以大端格式儲存。

#### 內容解密:

  1. open("Untitled.xcf", "rb"):以二進位模式開啟檔案 Untitled.xcf,並指定給 fp
  2. fp.read(100):讀取檔案的前 100 個位元組。
  3. header[:9].decode('ascii'):解碼前 9 個位元組以取得檔案格式名稱。
  4. struct.unpack('>I', ...):使用 struct 模組解析特定格式的二進位資料。

文字檔案操作

當以文字模式開啟檔案時,預設的編碼是 UTF-8。UTF-8 的優點在於它能夠快速判斷某個檔案是否不是 UTF-8 編碼,並且與 ASCII 向後相容。

fp = open("things.txt", "w")
fp.write("""\
one line
two lines
red line
blue line
""")
fp.close()
fpin = open("things.txt")
for line in fpin:
    print(line.strip())

#### 內容解密:

  1. open("things.txt", "w"):以寫入模式開啟檔案 things.txt
  2. fp.write(...):向檔案中寫入多行文字。
  3. for line in fpin::逐行讀取檔案內容,並列印出來。

檔案與目錄管理

Unix 系統中的檔案不僅僅是資料的集合,它們還具有各種可以被查詢和修改的元資料。os.rename 函式對檔案進行重新命名,這是一個原子操作,可以用來確保某些操作的原子性。

with open("important.tmp", "w") as fout:
    fout.write("The horse raced past the barn")
    fout.write("fell.\n")
os.rename("important.tmp", "important")

這個例子展示瞭如何安全地寫入一個重要的檔案,以避免在寫入過程中出現錯誤。

#### 內容解密:

  1. open("important.tmp", "w"):建立一個臨時檔案用於寫入。
  2. os.rename("important.tmp", "important"):將臨時檔案重新命名為目標檔案名稱,確保操作的原子性。

目錄管理

目錄是 Unix 系統中的特殊檔案。os.makedirs 函式可以用來建立目錄,如果目錄已經存在,可以透過設定 exist_ok=True 來避免引發例外。

os.makedirs(some_path, exist_ok=True)

#### 內容解密:

  1. os.makedirs(some_path, exist_ok=True):建立目錄,如果目錄已存在則不會引發錯誤。

Python 檔案與程式操作

Python 提供了豐富的模組來處理檔案和程式操作,本文將介紹如何使用 osshutilsubprocess 模組來進行檔案操作和程式管理。

安全的檔案寫入操作

在寫入檔案時,確保目錄存在是非常重要的。以下是一個範例函式,展示瞭如何安全地建立巢狀目錄並寫入檔案。

import os

def open_for_write(fname, mode=""):
    os.makedirs(os.path.dirname(fname), exists_ok=True)
    return open(fname, "w" + mode)

with open_for_write("some/deep/nested/name/of/file.txt") as fp:
    fp.write("hello world")

內容解密:

  1. os.makedirs 用於建立目錄,若目錄已存在則不會報錯,因為 exists_ok=True
  2. os.path.dirname(fname) 取得檔案路徑中的目錄部分。
  3. open(fname, "w" + mode) 以寫入模式開啟檔案,若檔案不存在則會建立。

檔案路徑操作

os.path 模組提供了許多字串操作函式,用於處理檔案路徑。

import os

# 取得目錄名稱
print(os.path.dirname("a/b/c"))  # 輸出: a/b

# 取得檔案名稱
print(os.path.basename("a/b/c"))  # 輸出: c

# 連線路徑
print(os.path.join("some", "long/and/winding", "path"))  # 輸出: some/long/and/winding/path

內容解密:

  1. os.path.dirname 傳回路徑中的目錄部分。
  2. os.path.basename 傳回路徑中的最後一個部分,即檔案或目錄名稱。
  3. os.path.join 將多個路徑部分連線成一個完整的路徑。

檔案後設資料操作

os.path 模組還提供了一些函式來取得檔案的後設資料。

import os

# 檢查檔案是否存在
print(os.path.exists("some/file.txt"))

# 檢查是否為目錄或檔案
print(os.path.isdir("some/dir"))
print(os.path.isfile("some/file.txt"))

# 取得檔案大小
print(os.path.getsize("some/file.txt"))

內容解密:

  1. os.path.exists 檢查檔案或目錄是否存在。
  2. os.path.isdiros.path.isfile 分別檢查給定的路徑是否為目錄或檔案。
  3. os.path.getsize 取得檔案的大小。

高階檔案操作

shutil 模組提供了更高階的檔案操作功能。

import shutil

# 複製檔案內容和後設資料
shutil.copy("source.txt", "destination.txt")

# 複製檔案內容
shutil.copyfile("source.txt", "destination.txt")

# 刪除目錄樹
shutil.rmtree("some/directory")

# 複製目錄樹
shutil.copytree("source/dir", "destination/dir")

內容解密:

  1. shutil.copy 複製檔案內容和後設資料。
  2. shutil.copyfile 只複製檔案內容。
  3. shutil.rmtree 刪除整個目錄樹。
  4. shutil.copytree 複製整個目錄樹。

臨時檔案的使用

Python 的 tempfile 模組可以用於建立安全的臨時檔案。

import tempfile

with tempfile.NamedTemporaryFile() as fp:
    fp.write(b"line 1\n")
    fp.write(b"line 2\n")
    fp.flush()
    # 使用臨時檔案的名稱
    function_taking_file_name(fp.name)

內容解密:

  1. tempfile.NamedTemporaryFile 建立一個安全的臨時檔案。
  2. 使用 with 陳述式確保檔案在使用後被正確關閉和刪除。
  3. fp.flush() 確保寫入的資料被重新整理到磁碟上。

程式操作

subprocess 模組用於執行外部命令和管理子程式。

import subprocess

# 高階函式:check_call 和 check_output
subprocess.check_call(["ls", "-l"])

# 低階別的 Popen 類別
process = subprocess.Popen(["ls", "-l"], stdout=subprocess.PIPE)
output, error = process.communicate()

內容解密:

  1. subprocess.check_call 執行命令並檢查其離開狀態,若非零則丟擲異常。
  2. subprocess.Popen 提供更細粒度的控制,可以組態輸入輸出串流。

安全地執行外部命令

避免使用 shell=True,因為它會引入安全風險,如命令注入攻擊。

# 安全的方式
subprocess.check_call(["usermod", "-G", "docker", "some-user"])

# 不安全的方式(避免這樣做)
subprocess.check_call("usermod -G docker some-user", shell=True)

內容解密:

  1. 直接傳遞命令和引數給 subprocess.check_call 是安全的。
  2. 使用 shell=True 可能導致安全問題,因為它會讓 shell 解析命令字串。

Python 中的 subprocess 模組與網路程式設計

在 Python 中,subprocess 模組提供了一種執行外部命令和程式的方法。這對於需要與系統命令或外部工具互動的指令碼和應用程式非常有用。同時,Python 也提供了豐富的網路程式設計支援,從底層的 socket 系統呼叫到高階的協定支援。

使用 subprocess 執行外部命令

subprocess 模組允許你以程式設計方式執行外部命令,並捕捉其輸出或檢查其離開狀態。其中,check_callcheck_output 是兩個常用的函式。

使用 check_call 執行命令

check_call 用於執行一個命令,並等待其完成。如果命令失敗(即傳回非零離開狀態),則會引發一個異常。

def add_to_docker(username):
    subprocess.check_call(["usermod", "-G", "docker", username])

這個函式將指定的使用者新增到 docker 群組中。如果 usermod 命令失敗,則會引發異常。

使用 check_output 捕捉命令輸出

check_output 執行一個命令,並傳回其輸出。如果命令失敗,則會引發一個異常。

groups = subprocess.check_output(["groups"]).split()

這行程式碼捕捉 groups 命令的輸出,並將其分割成一個列表。

自訂工作目錄

可以透過 cwd 引數指定命令執行時的工作目錄。

sha = subprocess.check_output(["git", "rev-parse", "HEAD"], cwd="src/some-project").decode("ascii").strip()

這段程式碼在 src/some-project 目錄中執行 git rev-parse HEAD 命令,以取得目前 Git 倉函式庫的 HEAD 提交雜湊。

處理較複雜的輸入/輸出需求

對於需要更精細控制輸入/輸出的情況,可以使用 Popen 類別。

使用 communicate 方法

communicate 方法允許你向子程式傳送資料,或讀取其輸出。

proc = subprocess.Popen(["docker", "login", "--password-stdin"], stdin=subprocess.PIPE)
out, err = proc.communicate(my_password.encode() + b"\n")

這段程式碼使用 Popen 執行 docker login 命令,並透過 communicate 方法傳送密碼。

處理長輸入

對於較長的輸入,可以使用暫存檔案來避免記憶體緩衝問題。

with tempfile.TemporaryFile() as fp:
    fp.write(contents)
    fp.write(of)
    fp.write(email)
    fp.flush()
    fp.seek(0)
    subprocess.check_call(["sendmail"], stdin=fp)

這段程式碼建立一個暫存檔案,將內容寫入其中,然後將該檔案用作 sendmail 命令的輸入。

網路程式設計

Python 提供了從底層 socket 到高階協定支援的豐富網路程式設計功能。

使用 socket 模組

sockets 模組提供了底層網路 API 的介面。

import socket
import json

s = socket.socket()
s.connect(('httpbin.org', 80))
s.sendall(b'GET /get HTTP/1.0\r\nHost: httpbin.org\r\n\r\n')
res = s.recv(1024)
data = res.decode('ascii').split('\r\n\r\n', 1)[1]
print(json.loads(data))

這段程式碼使用 socket 建立了一個到 httpbin.org 的連線,傳送了一個 HTTP GET 請求,並解析了回應。

#### 內容解密:

上述範例中,我們逐步解析了使用 subprocess 模組和網路程式設計的關鍵步驟。對於 subprocess,我們學習瞭如何使用 check_callcheck_output 執行外部命令,以及如何處理更複雜的輸入/輸出需求。在網路程式設計方面,我們瞭解瞭如何使用 socket 模組建立底層網路連線。這些技術在自動化、指令碼編寫和網路應用開發中非常有用。透過結合 Python 的內建功能和外部命令,可以編寫出強大且靈活的指令碼和應用程式。