說明
- 重點放在 .stat(),所有範例都可直接貼到 Jupyter Notebook 驗證。
- 我會先建立測試檔,再示範 Path.stat() 與 os.stat() 對照、欄位解讀、時間與權限處理、錯誤處理與實用範例。
一、準備測試檔與目錄
from pathlib import Path
import os, time
root = Path("stat_demo")
root.mkdir(exist_ok=True)
(p := root / "hello.txt").write_text("Hello World!\n", encoding="utf-8")
# 建一個子資料夾與空檔案
sub = root / "subdir"
sub.mkdir(exist_ok=True)
empty = sub / "empty.bin"
empty.touch()
root, p, sub, empty二、Path.stat() 與 os.stat() 對照
from pathlib import Path
import os
st1 = p.stat() # Path 物件的方法
st2 = os.stat(p) # os 模組函式(接受字串或 Path)
print(type(st1), type(st2)) # 都是 os.stat_result
assert st1 == st2
st1輸出:

三、最常用欄位快速查看
from datetime import datetime
st = p.stat()
print("檔案大小 bytes :", st.st_size)
print("最後內容修改時間 :", datetime.fromtimestamp(st.st_mtime))
print("最後存取時間 :", datetime.fromtimestamp(st.st_atime))
print("ctime(注意平台差異):", datetime.fromtimestamp(st.st_ctime))
print("st_mode(型態+權限):", st.st_mode)
print("inode/st_ino :", st.st_ino)
print("裝置 st_dev :", st.st_dev)
print("硬連結數 st_nlink :", st.st_nlink)
print("uid/gid :", st.st_uid, st.st_gid)輸出:

四、判讀 st_mode:檔案型態與權限
from stat import S_ISDIR, S_ISREG, S_ISLNK, S_IMODE
st = p.stat()
print("一般檔案?", S_ISREG(st.st_mode))
print("目錄? ", S_ISDIR(st.st_mode))
print("符號連結?", S_ISLNK(st.st_mode))
# 權限位(Unix 有意義;Windows 有限支援)
perm_octal = oct(S_IMODE(st.st_mode)) # 例如 '0o644'
print("權限(八進位):", perm_octal)輸出:

五、時間欄位的平台差異與格式化
- st_mtime/st_atime:最後修改內容、最後存取。
- st_ctime:Unix 是 metadata 變更時間;Windows 是建立時間。
from datetime import datetime, timezone
st = p.stat()
def fmt(ts):
return datetime.fromtimestamp(ts, tz=timezone.utc).astimezone().strftime("%Y-%m-%d %H:%M:%S %Z")
print("atime:", fmt(st.st_atime))
print("mtime:", fmt(st.st_mtime))
print("ctime:", fmt(st.st_ctime))輸出:

六、更新時間戳並觀察變化
# 先讀一次
before = p.stat().st_mtime
time.sleep(1.1)
# 修改內容以觸發 mtime 變更
with p.open("a", encoding="utf-8") as f:
f.write("Append one line.\n")
after = p.stat().st_mtime
print("mtime before:", before)
print("mtime after :", after)
print("changed? :", after > before)輸出:

七、目錄、空檔案與檔案大小
print("目錄 stat size(可能無意義):", sub.stat().st_size)
print("空檔案 size:", empty.stat().st_size, "bytes")
print("hello.txt size:", p.stat().st_size, "bytes")輸出:

八、錯誤處理:不存在的檔案
try:
(root / "not-exist.txt").stat()
except FileNotFoundError as e:
print("捕捉到錯誤:", type(e).__name__, e)輸出:

九、搭配 Path 其他常用檢查
print("exists:", p.exists())
print("is_file:", p.is_file())
print("is_dir:", p.is_dir())輸出:

十、把 stat() 結果整理成好讀的字典
from datetime import datetime
def stat_as_dict(path: Path):
st = path.stat()
d = {
"path": str(path),
"size": st.st_size,
"is_file": path.is_file(),
"is_dir": path.is_dir(),
"mode_octal": oct(S_IMODE(st.st_mode)),
"mtime": datetime.fromtimestamp(st.st_mtime).isoformat(sep=" ", timespec="seconds"),
"atime": datetime.fromtimestamp(st.st_atime).isoformat(sep=" ", timespec="seconds"),
"ctime": datetime.fromtimestamp(st.st_ctime).isoformat(sep=" ", timespec="seconds"),
"ino": st.st_ino,
"dev": st.st_dev,
"nlink": st.st_nlink,
"uid": st.st_uid,
"gid": st.st_gid,
}
return d
stat_as_dict(p)輸出:

十一、批次列出資料夾中每個檔案的 size 與 mtime
from datetime import datetime
rows = []
for fp in root.rglob("*"):
if fp.is_file():
st = fp.stat()
rows.append((str(fp.relative_to(root)), st.st_size, datetime.fromtimestamp(st.st_mtime)))
for name, size, mtime in sorted(rows):
print(f"{name:20s} {size:8d} bytes {mtime}")輸出:

十二、跨平台提醒與小結
- 時間欄位:特別注意 st_ctime 的語意因平台而異。
- 權限位:Windows 上的 st_mode/chmod 意義有限;Unix 才完整。
- Path.stat() 與 os.stat() 回傳同一種 os.stat_result;建議以 pathlib.Path 為主,必要時再搭配 os 函式。
加碼:快速取得檔案大小的兩種方式
# Path 方式
size1 = p.stat().st_size
# os.path 方式
import os
size2 = os.path.getsize(p)
size1, size2, size1 == size2輸出:

快速取得檔案大小
os.stat(p).st_size == p.stat().st_size == os.path.getsize(p)輸出:

絕對路徑
# %%
from pathlib import Path
import os
p = Path("stat_demo") / ".." / "stat_demo" / "hello.txt" # 人為加入 ..
print("原始相對路徑 :", p)
print("os.path.abspath :", os.path.abspath(p)) # 字串,規範化為絕對路徑
print("Path.absolute() :", p.absolute()) # Path,效果類似 abspath(不解析 symlink)
print("Path.resolve() :", p.resolve()) # Path,會規範化,也會嘗試解析真實路徑輸出:

推薦hahow線上學習python: https://igrape.net/30afN










近期留言