Python CLI จัดการไฟล์ให้ชัวร์ ด้วย Context Manager พร้อม Resilience

สวัสดีครับ เพื่อนๆ โปรแกรมเมอร์

วันนี้ผมมีเรื่องอยากจะมาคุยให้ฟัง เกี่ยวกับการทำ Python CLI ที่ต้องจัดการไฟล์เยอะๆ เนี่ยนะครับ บางทีเราเขียนโค้ดไป เราก็อยากให้มันทำงานแบบชัวร์ๆ ไม่ต้องกลัวไฟล์เสียหาย หรือโปรแกรมค้างกลางคัน ใช่ไหมครับ

ผมเลยอยากจะแนะนำ Context Manager กับแนวคิด Resilience มาใช้กับการจัดการ file-handling ใน python cli ของเรานี่แหละครับ มันช่วยให้โค้ดเราดูสะอาดขึ้น แล้วก็ทำงานได้ทนทานมากๆ เลยนะ

มาดูตัวอย่างกันเลยนะครับ

1. จัดการไฟล์แบบ Context Manager ทั่วไป: ปกติเวลาเราเปิดไฟล์ เราก็จะใช้ open() แบบนี้ใช่ไหมครับ แล้วก็ต้องมา close() เอง ถ้าลืม หรือ โปรแกรมมี error ตรงกลางเนี่ย ไฟล์อาจจะเปิดค้างได้เลยนะ

# โค้ดแบบเก่าๆ ที่อาจมีปัญหา
file = open('data.txt', 'w')
try:
    file.write('Hello World')
finally:
    file.close()

แต่ถ้าใช้ Context Manager มันจะง่ายกว่าเยอะเลยครับ แบบนี้เลยนะ:

# ใช้ Context Manager ให้โค้ดสะอาดขึ้น
with open('data.txt', 'w') as file:
    file.write('Hello World')
# ไม่ต้องเรียก file.close() เองแล้วครับ ระบบจัดการให้

2. เพิ่ม Resilience ให้กับการเขียนไฟล์: ทีนี้ ถ้าเกิดระหว่างที่เราเขียนไฟล์ เกิดมีอะไรผิดพลาดขึ้นมาละครับ เช่น ดิสก์เต็ม หรือไฟดับเนี่ย ข้อมูลเราอาจจะเสียหายได้นะ เราจะทำยังไงดี?

เทคนิคหนึ่งที่ผมชอบใช้ คือการเขียนไปที่ไฟล์ชั่วคราวก่อน temp file นะครับ แล้วค่อย Rename กลับมาทับไฟล์จริง ถ้าทุกอย่างโอเค

import os
import tempfile

def safe_write(filepath, content):
    # สร้างไฟล์ชั่วคราวในโฟลเดอร์เดียวกับไฟล์เป้าหมาย
    fd, temp_path = tempfile.mkstemp(dir=os.path.dirname(filepath))
    try:
        with os.fdopen(fd, 'w') as tmp_file:
            tmp_file.write(content)
        # ถ้าเขียนเสร็จสมบูรณ์ ค่อย rename ไฟล์ชั่วคราวมาทับไฟล์จริง
        os.replace(temp_path, filepath)
        print(f\"เขียนไฟล์ {filepath} สำเร็จแล้วครับ\")
    except Exception as e:
        print(f\"มีปัญหาตอนเขียนไฟล์ {filepath}: {e} ครับ\")
        # ถ้ามีปัญหา ให้ลบไฟล์ชั่วคราวทิ้ง
        os.remove(temp_path)

# ลองใช้งานดูนะครับ
safe_write('important_report.txt', 'รายงานลับสุดยอด\
ยังไม่เสร็จนะ')

เห็นไหมครับ แบบนี้ ถ้าเกิดมีอะไรผิดพลาดระหว่างเขียน ไฟล์ important_report.txt เดิมของเราก็จะยังอยู่ครบ ไม่พังนะครับ

3. รวม Resilience เข้ากับ Context Manager แบบง่ายๆ: เราสามารถสร้าง Context Manager ของเราเอง เพื่อรวมความสามารถนี้ได้นะ มันจะช่วยให้โค้ดเราดูโปรมากๆ เลยครับ

from contextlib import contextmanager
import os
import tempfile

@contextmanager
def resilient_file_writer(filepath):
    fd, temp_path = tempfile.mkstemp(dir=os.path.dirname(filepath))
    try:
        with os.fdopen(fd, 'w') as tmp_file:
            yield tmp_file # ส่ง object ไฟล์ให้ผู้ใช้
        # ถ้าไม่มี exception แปลว่าเขียนสำเร็จ ก็ rename
        os.replace(temp_path, filepath)
        print(f\"เขียนไฟล์ {filepath} สำเร็จด้วย resilient writer ครับ\")
    except Exception as e:
        print(f\"มีปัญหาตอนเขียนไฟล์ {filepath}: {e} ครับ\")
        os.remove(temp_path) # ลบไฟล์ชั่วคราวทิ้งถ้ามีปัญหา
        raise # โยน exception ให้ผู้ใช้จัดการต่อ

# ทีนี้มาลองใช้กันดูนะครับ
# กรณีสำเร็จ
with resilient_file_writer('config.json') as f:
    f.write('{ \"setting\": \"value\" }')

# กรณีมีปัญหา (สมมติ)
try:
    with resilient_file_writer('log.txt') as f:
        f.write('เริ่มทำงาน\
')
        raise ValueError(\"จำลอง error ในการเขียนไฟล์ครับ\") # จำลอง error
        f.write('เสร็จสิ้น') # โค้ดนี้จะไม่ถูกเรียก
except ValueError as e:
    print(f\"ผู้ใช้จับ error ได้: {e} ครับ\")

แบบนี้ก็เป็นการสร้าง CLI tool ของเราให้ resilient แล้วก็จัดการ file-handling ได้ดีขึ้นมากๆ เลยนะครับ ทำให้การ optimization ในเรื่องความเสี่ยงของข้อมูลที่เราเขียนทำได้ดียิ่งขึ้น

เพื่อนๆ ลองเอาเทคนิคนี้ไปปรับใช้กับโปรเจกต์ของตัวเองดูได้เลยนะครับ ผมว่ามันช่วยได้เยอะเลยแหละ

ขอให้สนุกกับการเขียนโค้ดนะครับ!

cii3.net

Read more

ดราม่า "เบิร์ด วันว่างๆ" กับยาแนว: บทเรียนสำคัญของอินฟลูเอนเซอร์และความปลอดภัยบนโซเชียล

ดราม่า "เบิร์ด วันว่างๆ" กับยาแนว: บทเรียนสำคัญของอินฟลูเอนเซอร์และความปลอดภัยบนโซเชียล

เจาะลึกดราม่า "เบิร์ด วันว่างๆ" ใช้ยาแนวเล่นสงกรานต์ คำชี้แจง และผลกระทบต่อสังคม บทเรียนสำคัญสำหรับความรับผิดชอบของอินฟลูเอนเซอร์

By ทีมงาน devdog
Xiaomi 17T หลุดสเปคเด็ดบน Geekbench! ยืนยัน Dimensity 8500 พร้อมแบต 7,000mAh จ่อเปิดตัว

Xiaomi 17T หลุดสเปคเด็ดบน Geekbench! ยืนยัน Dimensity 8500 พร้อมแบต 7,000mAh จ่อเปิดตัว

Xiaomi 17T เตรียมเปิดตัว! พบข้อมูลบน Geekbench ยืนยันใช้ชิป Dimensity 8500 พร้อมแบตเตอรี่จุใจ 7,000mAh คาดบุกตลาดรองเรือธงเร็วๆ นี้

By ทีมงาน devdog
กยศ. เปิดทางรอด! ปรับโครงสร้างหนี้ออนไลน์ หยุดถูกฟ้อง ก่อน 5 ก.ค. 69

กยศ. เปิดทางรอด! ปรับโครงสร้างหนี้ออนไลน์ หยุดถูกฟ้อง ก่อน 5 ก.ค. 69

ผู้กู้ กยศ. กว่า 1 แสนราย เสี่ยงถูกฟ้อง! รีบปรับโครงสร้างหนี้ออนไลน์ผ่านเป๋าตัง/ThaID ก่อน 5 ก.ค. 69 รับสิทธิประโยชน์ ลดดอกเบี้ย หลีกเลี่ยงคดีความ

By ทีมงาน devdog
Baseus MC2: หูฟังคลิปหนีบหูสุดล้ำ แบตอึด 60 ชม. เสียง LDAC กันน้ำ IP67 เพื่ออิสระทางเสียงของคุณ

Baseus MC2: หูฟังคลิปหนีบหูสุดล้ำ แบตอึด 60 ชม. เสียง LDAC กันน้ำ IP67 เพื่ออิสระทางเสียงของคุณ

พบ Baseus MC2 หูฟังคลิปหนีบหูดีไซน์ล้ำ สวมใส่สบายตลอดวัน ด้วยแบตเตอรี่ 60 ชม., กันน้ำ IP67, เสียง LDAC ระดับ Hi-Res และราคาเข้าถึงง่าย

By ทีมงาน devdog