Chuyển tới nội dung chính

🐍 Ngày 36 - Python hằng ngày 365 ngày - Làm việc với pathlib trong Python

🎯 Mục tiêu:​

  • Làm quen với thư viện pathlib để thao tác với file và thư mục một cách hiện đại và tiện lợi hơn os.

🔧 Nội dung:​

✅ Import thư viện​

from pathlib import Path

✅ Tạo một thư mục mới​

folder = Path("demo_folder")
folder.mkdir(exist_ok=True)
print(f"Đã tạo hoặc kiểm tra tồn tại: {folder}")

✅ Tạo một file trong thư mục đó​

file = folder / "hello.txt"
file.write_text("Chào bạn từ pathlib!")
print(f"Đã ghi file: {file}")

✅ Đọc lại nội dung file​

print("Nội dung file:", file.read_text())

📌 Ghi chú:​

  • Path() là cách khởi tạo đường dẫn.
  • / dùng để nối các thành phần đường dẫn (giống os.path.join()).
  • write_text() và read_text() giúp thao tác văn bản đơn giản hơn.

⏭ Tiếp tục với Ngày 37: Đọc ghi file JSON bằng pathlib + json


🔍 Vì sao pathlib tốt hơn os.path​

So sánh cùng một công việc:

Công việcos.path (cũ)pathlib (mới)
Nối đường dẫnos.path.join("a", "b", "c.txt")Path("a") / "b" / "c.txt"
Lấy tên fileos.path.basename(p)Path(p).name
Lấy phần mở rộngos.path.splitext(p)[1]Path(p).suffix
Lấy thư mục chaos.path.dirname(p)Path(p).parent
Kiểm tra tồn tạios.path.exists(p)Path(p).exists()
Đường dẫn tuyệt đốios.path.abspath(p)Path(p).resolve()
Đọc fileopen(p).read()Path(p).read_text()

Lợi ích lớn nhất: Path là đối tượng, không phải chuỗi. Bạn có thể gọi method trên nó, nối bằng /, và code chạy đúng trên cả Windows và Linux.

from pathlib import Path

# Trên Windows: Path("data") / "nam-2026" / "bao-cao.csv"
# → data\nam-2026\bao-cao.csv
# Trên Linux: → data/nam-2026/bao-cao.csv
# CÙNG MỘT DÒNG CODE, đúng cả hai nơi
file = Path("data") / "nam-2026" / "bao-cao.csv"

🛠️ Các thuộc tính và method quan trọng​

from pathlib import Path

p = Path("data/bao-cao-2026.csv")

# --- Thuộc tính ---
print(p.name) # bao-cao-2026.csv
print(p.stem) # bao-cao-2026 (không có phần mở rộng)
print(p.suffix) # .csv
print(p.parent) # data
print(p.parts) # ('data', 'bao-cao-2026.csv')
print(p.is_absolute()) # False
print(p.anchor) # '' trên Linux, 'C:\\' trên Windows

# --- Kiểm tra ---
print(p.exists()) # File có tồn tại?
print(p.is_file()) # Là file?
print(p.is_dir()) # Là thư mục?

# --- Chuyển đổi ---
print(p.resolve()) # Đường dẫn tuyệt đối, đã chuẩn hoá
print(p.with_suffix(".json")) # data/bao-cao-2026.json
print(p.with_name("khac.csv")) # data/khac.csv

📂 Tạo, di chuyển, xoá​

from pathlib import Path
import shutil

thu_muc = Path("du-an")

# Tạo thư mục (exist_ok=True để không lỗi nếu đã có)
thu_muc.mkdir(parents=True, exist_ok=True)

# Tạo nhiều thư mục con cùng lúc
for ten in ("du-lieu", "bao-cao", "log"):
(thu_muc / ten).mkdir(exist_ok=True)

# Ghi và đọc text
file = thu_muc / "ghi-chu.txt"
file.write_text("Nội dung ghi chú", encoding="utf-8")
print(file.read_text(encoding="utf-8"))

# Ghi và đọc nhị phân (ảnh, file nén...)
anh = thu_muc / "logo.png"
# anh.write_bytes(du_lieu_nhi_phan)
# du_lieu = anh.read_bytes()

# Di chuyển / đổi tên
dich = thu_muc / "ghi-chu-moi.txt"
file.rename(dich)

# Sao chép (dùng shutil)
shutil.copy2(dich, thu_muc / "sao-chep.txt")

# Xoá file
if dich.exists():
dich.unlink()

# Xoá thư mục rỗng
# (thu_muc / "rong").rmdir()

⚠️ unlink() và rmdir() không hỏi lại. Nếu bạn chạy Path("du-lieu").unlink() mà trỏ nhầm vào file quan trọng, nó mất ngay. Không có thùng rác. Hãy kiểm tra kỹ đường dẫn trước khi xoá — và không bao giờ dùng vòng lặp unlink() mà không xem danh sách trước.

🔎 Tìm file với glob​

from pathlib import Path

thu_muc = Path("du-an")

# Tất cả file .csv trong thư mục này
for f in thu_muc.glob("*.csv"):
print(f.name)

# Tất cả file .csv trong MỌI thư mục con
for f in thu_muc.rglob("*.csv"):
print(f.relative_to(thu_muc))

# Nhiều mẫu cùng lúc
for mau in ("*.csv", "*.xlsx", "*.json"):
for f in thu_muc.rglob(mau):
print(f"{f.stat().st_size:>10,} bytes {f.name}")

# Chỉ lấy file (bỏ thư mục)
file_csv = [f for f in thu_muc.rglob("*.csv") if f.is_file()]
print(f"Tìm thấy {len(file_csv)} file CSV")

Bảng mẫu glob hay dùng:

MẫuKhớp với
*.txtMọi file .txt
bao-cao-*.csvBắt đầu bằng bao-cao-
2026-??.xlsx? = đúng một ký tự bất kỳ
**/*.pyMọi file .py trong mọi thư mục con

Thông tin file​

from pathlib import Path
from datetime import datetime

f = Path("du-an/bao-cao.csv")
if f.exists():
st = f.stat()
print(f"Kích thước: {st.st_size / 1024:.1f} KB")
print(f"Sửa lần cuối: {datetime.fromtimestamp(st.st_mtime):%d/%m/%Y %H:%M}")

🧹 Ứng dụng thực tế: dọn file cũ hơn 30 ngày​

from pathlib import Path
from datetime import datetime, timedelta


def don_file_cu(thu_muc: Path, so_ngay: int = 30, mo_phong: bool = True) -> int:
"""Xoá file cũ hơn `so_ngay` ngày. Mặc định chỉ MÔ PHỎNG."""
han = datetime.now() - timedelta(days=so_ngay)
so_luong = 0

for f in thu_muc.rglob("*.log"):
if not f.is_file():
continue

ngay_sua = datetime.fromtimestamp(f.stat().st_mtime)
if ngay_sua < han:
if mo_phong:
print(f"[MÔ PHỎNG] sẽ xoá: {f} (sửa {ngay_sua:%d/%m/%Y})")
else:
f.unlink()
print(f"Đã xoá: {f}")
so_luong += 1

return so_luong


# Luôn chạy mô phỏng trước!
print(don_file_cu(Path("logs"), so_ngay=30, mo_phong=True))

📝 Bài tập mở rộng​

Bài 1: Đếm file theo loại​

Tạo cấu trúc thư mục với nhiều loại file khác nhau, rồi viết script đếm số file mỗi loại (.py, .csv, .txt, .json) và tổng dung lượng.

Bài 2: Đổi tên hàng loạt​

Đổi tên mọi file .jpeg thành .jpg trong một thư mục (dùng with_suffix()).

Bài 3: Tìm file trùng tên trong nhiều thư mục​

Dùng rglob() và collections.Counter để tìm file có cùng tên ở nhiều nơi.

Bài 4: Cây thư mục​

In ra cây thư mục (giống lệnh tree) từ một thư mục, dùng đệ quy để đi vào thư mục con.

🎯 Tóm tắt ngày 36​

✅ Dùng Path thay os.path — code sạch hơn, chạy đa nền tảng ✅ Nối đường dẫn bằng dấu / ✅ mkdir(parents=True, exist_ok=True) tạo thư mục an toàn ✅ read_text/write_text gọn hơn open() ✅ glob/rglob tìm file theo mẫu ✅ Luôn chạy mô phỏng trước khi xoá file


🚀 Bắt đầu với Python

Bạn có thể mở bài học này trên Google Colab để chạy trực tiếp:

Mở trên Colab