Ejen AI · Pelajaran

Operasi Fail Selamat dengan Pengendalian Ralat

Menyemak kewujudan fail dan keizinan serta mengendalikan ralat IO dengan baik.

Pelajaran 4 daripada 413 langkah

Operasi Fail Selamat dengan Pengendalian Ralat ialah pelajaran Ejen AI percuma di CoddyKit. Ini ialah pelajaran 4 daripada 4. Anda boleh membaca keseluruhan pelajaran di bawah secara percuma — kemudian berlatih secara praktikal dalam pelayar menggunakan penyunting kod terbina dalam dan tutor kecerdasan buatan 24/7. Pelajaran ini merupakan sebahagian daripada laluan pembelajaran Ejen AI, dan kemajuan anda disegerakkan merentas web serta aplikasi CoddyKit. Kursus Ejen AI merangkumi sejumlah 4 pelajaran.

Mengapa Operasi Fail yang Selamat Penting

Operasi fail dalam ejen boleh gagal dalam banyak keadaan: fail tidak wujud, ejen tidak mempunyai kebenaran, laluan ialah direktori atau ruang cakera habis semasa penulisan. Ejen yang ranap akibat ralat fail akan meninggalkan keluaran separa dan keadaan yang rosak. Pengaturcaraan defensif dengan pemeriksaan serta pengendalian ralat yang betul menjadikan ejen lebih teguh.

from pathlib import Path

# Unsafe: crashes with FileNotFoundError
# content = Path('missing.txt').read_text()

# Safe: check first
path = Path('config.json')
if path.exists():
    content = path.read_text(encoding='utf-8')
    print('Loaded config')
else:
    print(f'Config not found at {path.resolve()}')
    content = '{}'  # use default

Path.exists() dan Path.is_file()

Sebelum membaca fail, semak bahawa fail itu wujud dan benar-benar merupakan fail biasa (bukan direktori, pautan simbolik ke direktori atau fail khas). Path.exists() mengembalikan True untuk sebarang objek sistem fail; Path.is_file() mengembalikan True hanya untuk fail biasa.

from pathlib import Path

path = Path('data/report.csv')

# Chain of checks
if not path.exists():
    print(f'Not found: {path}')
elif not path.is_file():
    print(f'Not a regular file: {path} (is_dir={path.is_dir()})')
elif path.stat().st_size == 0:
    print(f'File is empty: {path}')
else:
    # Safe to read
    import csv
    with open(path, 'r', encoding='utf-8', newline='') as f:
        reader = csv.DictReader(f)
        rows = list(reader)
    print(f'Read {len(rows)} rows')

os.access() — Menyemak Kebenaran

os.access(path, mode) menyemak sama ada proses semasa mempunyai kebenaran yang ditentukan pada sesuatu fail. Gunakan os.R_OK untuk membaca, os.W_OK untuk menulis dan os.X_OK untuk melaksanakan. Ini berguna sebelum mencuba operasi yang memerlukan kebenaran tertentu.

import os
from pathlib import Path

def check_file_access(path):
    p = Path(path)

    checks = {
        'exists': p.exists(),
        'is_file': p.is_file(),
        'readable': os.access(p, os.R_OK),
        'writable': os.access(p, os.W_OK),
    }

    for check, result in checks.items():
        status = 'OK' if result else 'FAIL'
        print(f'  {check}: {status}')

    return all(checks.values())

if check_file_access('data/input.json'):
    print('File is accessible')
else:
    print('Access problem — check path and permissions')

Menangkap FileNotFoundError

FileNotFoundError (subkelas OSError) dicetuskan apabila anda cuba membuka fail yang tidak wujud. Tangkapnya secara khusus dan berikan mesej ralat yang berguna, termasuk laluan yang dijangka, supaya pengguna atau pengendali mengetahui perkara yang tiada dengan tepat.

import json
from pathlib import Path

def load_agent_config(config_path='agent_config.json'):
    path = Path(config_path)
    try:
        with open(path, 'r', encoding='utf-8') as f:
            return json.load(f)
    except FileNotFoundError:
        print(f'Config file not found: {path.resolve()}')
        print('Create agent_config.json with your settings')
        print('Example: {"model": "gpt-4o", "max_retries": 3}')
        return {}  # return empty config as default
    except json.JSONDecodeError as e:
        print(f'Invalid JSON in {path}: {e}')
        return {}

# --- demo ---
config = load_agent_config('does_not_exist_config.json')
print(f'Config used: {config}')

Menangkap PermissionError

PermissionError dicetuskan apabila proses tidak mempunyai kebenaran untuk membaca atau menulis fail. Keadaan ini boleh berlaku pada fail sistem, fail milik pengguna lain atau fail dengan kebenaran yang ketat. Sentiasa tangkapnya secara berasingan daripada FileNotFoundError — kedua-duanya memerlukan tindakan yang berbeza.

from pathlib import Path

def read_file_safely(path):
    try:
        return Path(path).read_text(encoding='utf-8')
    except FileNotFoundError:
        print(f'File not found: {path}')
        return None
    except PermissionError:
        import os
        print(f'Permission denied: {path}')
        print(f'File permissions: {oct(Path(path).stat().st_mode)}')
        print(f'Current user: {os.getlogin()}')
        print('Try: chmod +r ' + str(path))
        return None
    except IsADirectoryError:
        print(f'Path is a directory, not a file: {path}')
        return None

# --- demo ---
import os
print(read_file_safely('does_not_exist.txt'))

os.makedirs('a_directory', exist_ok=True)
print(read_file_safely('a_directory'))

Menangkap IsADirectoryError

IsADirectoryError dicetuskan apabila anda cuba membuka direktori seolah-olah ia sebuah fail. Keadaan ini boleh berlaku apabila ejen membina laluan secara salah — contohnya, menambahkan nama fail yang sebenarnya sudah wujud sebagai direktori. Sentiasa tangkapnya supaya output ralat yang diberikan bermakna.

from pathlib import Path

def safe_write(output_path, content):
    path = Path(output_path)

    # Check the path is not an existing directory
    if path.is_dir():
        raise IsADirectoryError(
            f'Cannot write file: {path} is a directory. '
            f'Use a filename like {path}/output.txt instead.'
        )

    # Ensure parent directory exists
    path.parent.mkdir(parents=True, exist_ok=True)

    try:
        path.write_text(content, encoding='utf-8')
        print(f'Written: {path} ({len(content)} chars)')
    except IsADirectoryError as e:
        print(f'Path error: {e}')
    except PermissionError:
        print(f'Cannot write to {path} — permission denied')

# --- demo ---
import os
safe_write('demo_output/report.txt', 'Agent finished the task.')

os.makedirs('already_a_dir', exist_ok=True)
try:
    safe_write('already_a_dir', 'this will fail')
except IsADirectoryError as e:
    print(f'Rejected: {e}')

Penulisan Atom dengan Fail Sementara

Menulis terus ke dalam fail adalah berbahaya — jika ejen ranap ketika proses penulisan berlangsung, fail itu akan menjadi separa ditulis dan rosak. Penyelesaiannya ialah penulisan atom: tulis dahulu ke dalam fail sementara, kemudian namakannya semula kepada laluan akhir. Penamaan semula adalah atom pada sistem POSIX — fail akhir sama ada versi lama atau versi baharu, tidak pernah versi separa.

import tempfile
import os
import json
from pathlib import Path

def atomic_write_json(file_path, data):
    path = Path(file_path)
    path.parent.mkdir(parents=True, exist_ok=True)

    # Write to temp file in same directory
    tmp_fd, tmp_path = tempfile.mkstemp(
        dir=path.parent,
        prefix='.tmp_',
        suffix='.json'
    )
    try:
        with os.fdopen(tmp_fd, 'w', encoding='utf-8') as f:
            json.dump(data, f, indent=2, ensure_ascii=False)
        # Atomic rename: replaces final file in one operation
        os.replace(tmp_path, path)
        print(f'Atomically wrote: {path}')
    except Exception as e:
        os.unlink(tmp_path)  # clean up temp file on error
        raise

# --- demo ---
atomic_write_json('demo_state/state.json', {'step': 3, 'status': 'running'})
print('File contents:', Path('demo_state/state.json').read_text(encoding='utf-8'))

Penguncian Fail untuk Ejen Serentak

Apabila beberapa tika ejen berjalan secara selari dan menulis ke fail yang sama, keadaan perlumbaan boleh merosakkan data. Gunakan penguncian fail dengan modul fcntl (Linux/macOS) atau pustaka filelock merentas platform untuk menghalang penulisan serentak.

from filelock import FileLock, Timeout
import json
from pathlib import Path

COUNTER_FILE = Path('shared_counter.json')
LOCK_FILE = Path('shared_counter.json.lock')

def increment_counter():
    lock = FileLock(str(LOCK_FILE), timeout=10)
    try:
        with lock:
            # Only one process can be here at a time
            if COUNTER_FILE.exists():
                data = json.loads(COUNTER_FILE.read_text())
            else:
                data = {'count': 0}

            data['count'] += 1
            COUNTER_FILE.write_text(
                json.dumps(data, indent=2)
            )
            return data['count']
    except Timeout:
        print('Could not acquire lock within 10 seconds')
        return None

Pemadaman Selamat dengan Semakan Kewujudan

Memadam fail yang tidak wujud akan mencetuskan FileNotFoundError. Memadam direktori dengan Path.unlink() akan mencetuskan IsADirectoryError. Gunakan Path.unlink(missing_ok=True) (Python 3.8+) atau semak kewujudan terlebih dahulu untuk pemadaman yang selamat.

from pathlib import Path
import shutil

# Safe file deletion (Python 3.8+)
Path('temp_output.json').unlink(missing_ok=True)

# Safe directory deletion
def safe_remove(path):
    p = Path(path)
    if not p.exists():
        print(f'Already gone: {p}')
        return
    if p.is_file():
        p.unlink()
        print(f'Deleted file: {p}')
    elif p.is_dir():
        shutil.rmtree(p)
        print(f'Deleted directory: {p}')
    else:
        print(f'Unknown file type: {p}')

# Clean up temporary workspace
safe_remove('/tmp/agent_workspace/run_001')

Semakan Ruang Cakera Sebelum Menulis

Ejen yang menulis fail besar (output AI, set data, log) hendaklah menyemak ruang cakera yang tersedia terlebih dahulu. shutil.disk_usage(path) mengembalikan bait keseluruhan, digunakan dan bebas. Pastikan ruang bebas melebihi saiz output yang dijangka sebelum memulakan operasi penulisan yang panjang.

import shutil
from pathlib import Path

def check_disk_space(output_dir, required_bytes):
    path = Path(output_dir)
    path.mkdir(parents=True, exist_ok=True)

    usage = shutil.disk_usage(path)
    free_gb = usage.free / (1024 ** 3)
    required_gb = required_bytes / (1024 ** 3)

    print(f'Disk free: {free_gb:.2f} GB')
    print(f'Required:  {required_gb:.2f} GB')

    if usage.free < required_bytes * 1.1:  # 10% safety margin
        raise IOError(
            f'Insufficient disk space: '
            f'{free_gb:.2f} GB free, '
            f'{required_gb:.2f} GB required'
        )
    return True

# Before writing a 500 MB dataset
check_disk_space('/tmp/output', 500 * 1024 * 1024)

Sandaran Sebelum Menulis Ganti

Apabila ejen mengemas kini fail sedia ada, sebaik-baiknya simpan sandaran versi sebelumnya. Dengan cara ini, anda boleh membuat pemulihan jika kandungan baharu tidak betul. Gunakan nama fail sandaran bertanda masa dan hadkan bilangan sandaran supaya ruang cakera tidak penuh.

import shutil
import datetime
from pathlib import Path

def write_with_backup(file_path, content, max_backups=5):
    path = Path(file_path)
    backup_dir = path.parent / '.backups'
    backup_dir.mkdir(exist_ok=True)

    # Backup existing file
    if path.exists():
        timestamp = datetime.datetime.now().strftime('%Y%m%d_%H%M%S')
        backup = backup_dir / f'{path.name}.{timestamp}'
        shutil.copy2(path, backup)
        print(f'Backed up to: {backup}')

    # Write new content
    path.write_text(content, encoding='utf-8')

    # Prune old backups
    backups = sorted(backup_dir.glob(f'{path.name}.*'))
    for old in backups[:-max_backups]:
        old.unlink()
        print(f'Pruned old backup: {old.name}')

# --- demo ---
write_with_backup('demo_notes.txt', 'version 1')
write_with_backup('demo_notes.txt', 'version 2')
print('Backups:', [p.name for p in sorted(Path('.backups').glob('demo_notes.txt.*'))])

Semakan Pantas: Penulisan Atom

Uji pemahaman anda tentang corak penulisan fail yang selamat.

Ringkasan Operasi Fail Selamat

Ejen anda kini boleh mengendalikan fail secara defensif:

  • Semak sebelum mengakses: Path.exists() + Path.is_file() + os.access(path, os.R_OK)
  • Tangkap FileNotFoundError, PermissionError dan IsADirectoryError dengan mesej yang jelas
  • Gunakan penulisan atom (fail sementara + os.replace) untuk menghalang fail separa atau rosak apabila berlaku ranap
  • Gunakan penguncian fail (pustaka filelock) apabila beberapa ejen menulis ke fail yang sama
  • Gunakan missing_ok=True untuk pemadaman selamat tanpa FileNotFoundError
  • Semak ruang cakera sebelum penulisan besar; simpan sandaran sebelum menulis ganti fail penting
Percuma untuk bermula

Pelajari Ejen AI dengan tutor kecerdasan buatan — percuma

Tulis dan jalankan kod sebenar dalam pelayar anda, dapatkan bantuan segera daripada tutor kecerdasan buatan yang tersedia 24/7, dan sambung semula dari tempat anda berhenti di web atau dalam aplikasi.

Kursus
60
Pelajaran
239

Soalan Lazim

Adakah pelajaran “Operasi Fail Selamat dengan Pengendalian Ralat” percuma?

Ya — teks penuh “Operasi Fail Selamat dengan Pengendalian Ralat” boleh dibaca secara percuma di web ini. Untuk berlatih secara interaktif menggunakan penyunting kod terbina dalam dan tutor kecerdasan buatan 24/7, serta membuka kunci baki kursus Ejen AI, tingkat taraf kepada CoddyKit PRO. Kursus Ejen AI merangkumi sejumlah 4 pelajaran.

Apakah yang akan saya pelajari dalam “Operasi Fail Selamat dengan Pengendalian Ralat”?

Menyemak kewujudan fail dan keizinan serta mengendalikan ralat IO dengan baik. Anda berlatih Ejen AI menggunakan kod praktikal yang dijalankan terus dalam pelayar, manakala tutor kecerdasan buatan 24/7 menjawab soalan anda semasa anda mengikuti pelajaran.

Adakah saya memerlukan pengalaman untuk memulakan Ejen AI?

Tiada pengalaman terdahulu diperlukan. Pembelajaran Ejen AI di CoddyKit disusun untuk pelajar daripada peringkat pemula hingga lanjutan, jadi anda boleh bermula di sini atau dari awal dan belajar mengikut kadar anda sendiri. Ini ialah pelajaran 4 daripada 4.

Berapa lamakah pelajaran “Operasi Fail Selamat dengan Pengendalian Ralat” diambil?

Kebanyakan pelajaran CoddyKit mengambil masa kira-kira 5–10 minit. Setiap pelajaran ringkas dan interaktif, jadi anda boleh membuat kemajuan secara berterusan dan menyambung tepat dari tempat anda berhenti di web atau aplikasi.

Bolehkah saya menulis dan menjalankan kod dalam pelajaran Ejen AI ini?

Ya. Setiap pelajaran Ejen AI menyertakan penyunting kod terbina dalam, jadi anda boleh menulis dan menjalankan kod sebenar terus dalam pelayar serta menerima maklum balas kecerdasan buatan serta-merta — tanpa memerlukan persediaan setempat.

Semua pelajaran dalam kursus ini

  1. Membaca dan Menulis Fail dalam Konteks Ejen
  2. Penjelajahan Direktori dan Penemuan Fail
  3. Pengendalian Format Fail: CSV, JSON dan TXT
  4. Operasi Fail Selamat dengan Pengendalian Ralat
← Kembali ke Ejen AI