スクリプト・ファイル自動化

フォルダー内のファイル一覧をCSVにまとめる

サブフォルダーまで調べ、ファイルのパス、拡張子、サイズ、更新時刻を表に記録します。小さなサンプルファイル4個から始め、元のファイルと既存の結果を保管します。

目次を表示

この翻訳はAIで作成しました。コード、単位、数値は原文と併せて確認してください。各言語のネイティブ話者による校閲は、まだ完了していません。 한국어

対象読者フォルダー内の文書数や保存場所を手作業で整理してきたPython初心者

準備するもの
  • Python 3.12以上を用意し、ターミナルでpython --versionを実行してバージョンを確認します。
  • サンプルZIPを新しいフォルダーに展開します。圧縮ファイルの中から直接実行しないでください。
  • example.pyがあるフォルダーでターミナルを開きます。Windowsでpythonコマンドがない場合はpyを、macOS・Linuxでは環境に応じてpython3を使います。
  • 外部パッケージのインストールやアカウントは不要です。同梱の資料は、独自に作成した合成データです。

01四つのファイルで最初の一覧を作る

フォルダーが作成されただけでは、この作業は完了ではありません。CSVに元の四つのファイルが一回ずつ入り、表示されたバイト数の合計が63で、元の内容が変わっていないことが必要です。まず同梱の資料でこの条件を確認してから、自分の業務フォルダーに広げてください。

  1. 展開したフォルダーでexample.py、README.txt、sample_filesフォルダーを確認します。
  2. sample_filesを開き、readme.txt、empty.txt、docsとreportsのサブフォルダーを確認します。empty.txtは意図的に空にしてあります。
  3. ターミナルで以下のコマンドを一回実行します。実行中は入力ファイルを移動したり編集したりしないでください。
  4. 完了メッセージと出力先のパスが表示されたら、outputs/file_list.csvを開きます。
bash
python example.py

02パスと各列の意味を理解する

コードは、ターミナルの現在のフォルダーではなく、example.pyの保存場所を基準にします。BASEの下にあるsample_filesだけを調べるため、サンプルフォルダー全体を移動しても、相対的な配置が同じなら動作します。outputsは調査対象の外に置き、結果のCSVが再び入力一覧に混ざらないようにしています。

意味読むときの確認点
relative_pathsample_filesを基準とする相対パス同じ名前でも、フォルダーが異なれば区別できます。
extension最後の拡張子を小文字で表示拡張子がない場合は(없음)と表示され、tar.gzの場合は.gzになります。
size_bytesファイルサイズをバイト単位の整数で表示0は空のファイルを示し、欠落を意味しません。
modified_utcUTCで表したファイルの更新時刻末尾の+00:00はUTCを示し、韓国の現地時刻とは異なります。

relative_pathは、OSが異なっても読みやすいようにスラッシュで表示します。結果はこのパスを基準に並べ替えます。ファイル探索の内部的な順序に依存しないため、同じ入力の行順を比較しやすくなります。

03実行に使うコード全体

collect_filesは情報の収集、mainは新しいCSVへの書き込みを担当します。入力の確認が終わるまでoutputsは作成しません。読み取れないフォルダーやリンクが見つかった場合は、一部だけの一覧を成功した結果として保存せず、処理を停止します。

example.py
"""sample_files를 읽어 outputs/file_list.csv에 목록을 기록합니다. 원본은 변경하지 않습니다."""

import csv
import os
import sys
from datetime import datetime, timezone
from pathlib import Path

BASE = Path(__file__).resolve().parent
INPUT = BASE / "sample_files"
OUTPUT = BASE / "outputs"
FIELDS = ["relative_path", "extension", "size_bytes", "modified_utc"]


def is_link(path):
    # Windows 연결 디렉터리(junction)도 Python 3.12 이상에서는 거부합니다.
    return path.is_symlink() or getattr(path, "is_junction", lambda: False)()


def collect_files(folder):
    if is_link(folder) or not folder.is_dir():
        raise ValueError("sample_files는 실제 폴더여야 합니다.")
    rows = []

    def stop_on_error(error):
        raise error

    # 하위 폴더까지 읽되, 링크를 따라 다른 폴더로 나가지 않습니다.
    for root, dirs, files in os.walk(folder, followlinks=False, onerror=stop_on_error):
        root = Path(root)
        for name in dirs + files:
            if is_link(root / name):
                raise ValueError(f"링크는 처리하지 않습니다: {root / name}")
        for name in sorted(files):
            path = root / name
            if not path.is_file():
                raise ValueError(f"일반 파일이 아닙니다: {path}")
            stat = path.stat()
            rows.append({
                "relative_path": path.relative_to(folder).as_posix(),
                "extension": path.suffix.lower() or "(없음)",
                "size_bytes": stat.st_size,
                "modified_utc": datetime.fromtimestamp(
                    stat.st_mtime, timezone.utc
                ).isoformat(timespec="seconds"),
            })
    return sorted(rows, key=lambda row: row["relative_path"])


def main():
    if OUTPUT.exists() or OUTPUT.is_symlink():
        raise FileExistsError("outputs가 이미 있습니다. 기존 결과를 옮긴 뒤 실행하세요.")
    rows = collect_files(INPUT)  # 모두 읽은 뒤에만 출력 폴더를 만듭니다.
    OUTPUT.mkdir()
    target = OUTPUT / "file_list.csv"
    # x는 기존 파일을 덮어쓰지 않는 모드입니다. BOM은 한글 CSV 열기에 도움을 줍니다.
    with target.open("x", encoding="utf-8-sig", newline="") as stream:
        writer = csv.DictWriter(stream, fieldnames=FIELDS)
        writer.writeheader()
        writer.writerows(rows)
    print(f"완료: {len(rows)}개 파일, 합계 {sum(row['size_bytes'] for row in rows)}바이트")
    print(target)
    return 0


if __name__ == "__main__":
    try:
        raise SystemExit(main())
    except (OSError, ValueError) as error:
        print(f"중지: {error}", file=sys.stderr)
        raise SystemExit(2)

CSVの列区切りと引用符はcsv.DictWriterが処理します。newlineに空文字列を指定し、UTF-8 BOM付きで保存します。出力ファイルはxモードで開き、同名のファイルがすでに作られていても上書きしません。この例では、その前にoutputsフォルダー自体の存在を確認します。

04結果の四行と合計を照合する

relative_pathextensionsize_bytes
docs/agenda.txt.txt15
empty.txt.txt0
readme.txt.txt17
reports/sales.csv.csv31

上の表の合計は15 + 0 + 17 + 31 = 63バイトです。ターミナルにも「완료: 4개 파일, 합계 63바이트」という完了メッセージが表示されます。CSVの先頭行は列名なので、スプレッドシートではヘッダーを含めて五行になります。empty.txtを数え忘れないようにしてください。

05一覧だけでなく元のファイルの保全も確認する

  1. CSVにある四つのファイルパスを、sample_files内の実際の場所と一つずつ照合します。docsとreportsのフォルダー自体は、データ行には入りません。
  2. 空のファイルが0バイトとして含まれ、拡張子が.txtと.csvに分かれているか確認します。
  3. sample_files/readme.txtを開き、元のSample inventoryという文が残っているか確認します。
  4. 同じコマンドをもう一度実行します。「outputs가 이미 있습니다」という停止メッセージが表示され、最初の結果が保持されることを確認します。

失敗条件も、正常な設計の一部です。再実行できないからといって、出力を拒否するコードを削除しないでください。前の結果が必要なら、outputsを日付入りの別名に変更して保管してから再実行するか、ZIPを新しいフォルダーに展開して新たに試します。

06自分のフォルダーに適用する手順

最初から業務フォルダー全体を対象にせず、代表的なファイルをいくつかsample_filesのコピーに入れてみてください。韓国語や空白を含むファイル名も、パスオブジェクトで扱います。ただし、別の場所につながるシンボリックリンクやリンクされたディレクトリは対象外なので、通常のファイルだけを含む小さなコピーが適しています。

  1. 元のサンプル入力と結果を保管し、新しい練習フォルダーを作ります。
  2. 手作業で数えられる5~10個のファイルをsample_filesに置きます。一段のサブフォルダーも作ってみてください。
  3. 一覧を生成し、相対パスが期待する場所を指しているか確認します。
  4. 確認したルールを維持したまま、対象ファイル数を増やします。ファイルサイズは内容の長さと異なる場合があるため、単位はバイトのままにします。

入力フォルダーが空の場合は、ヘッダーだけのCSVが生成され、ファイル数は0と表示されます。これは、フォルダーが存在せず処理が止まる場合とは異なります。空のフォルダーも業務上の正常な状態になり得るため、結果を解釈するときは区別してください。

07よくあるエラーを解決する

症状考えられる原因次に行うこと
pythonコマンドが見つからない実行環境のインストールまたはパス設定の問題まずpython --versionを確認し、Windowsではpyを試します。
sample_filesが実際のフォルダーではないフォルダーがない、またはリンクを使っているZIP全体を展開したか確認し、実際のフォルダーを復元します。
outputsがすでに存在する前回の実行結果が残っている既存の結果を別の場所に保管してから、再実行します。
韓国語の文字が正しく表示されない開くプログラムによる文字コードの解釈に問題があるCSVのインポート時にUTF-8を指定し、元のファイルは変更しません。
読み取り権限のエラーアクセスできないフォルダー、またはロックされたパスまずアクセス可能な練習用コピーに対象を絞ります。

08この一覧が保証する範囲

この結果は、実行中に確認したファイル情報です。内容が同じかを比較する重複検査でも、復元可能なバックアップでもありません。ファイルサイズが同じ二つの文書でも、内容は異なることがあります。ハッシュ比較が必要な場合は、その目的と専用の列を別途追加する必要があります。

この入門例では、調査中に別のプログラムがファイル名や内容を変える場合、ネットワークドライブの遅延、非常に多くのファイルを一度にメモリへ集める場合は扱いません。出力中にディスクへの書き込みが失敗すると、不完全なoutputsが残る場合があります。完了メッセージと結果の行数を併せて確認してください。

実行・検証の記録

2026-09-19 · Windows 11 · CPython 3.12.14 · 追加パッケージなし · 配布版の一時コピーで実行

  • 入れ子のフォルダーを含む4個のファイルと、合計63バイトを確認
  • 空の入力フォルダーではヘッダーのみを出力
  • 存在しない入力フォルダーと既存のoutputsを拒否
  • 別の作業フォルダーから実行し、パスの独立性を確認
  • 入力ファイルのSHA-256が実行前後で一致することを確認
検証範囲の限界
  • macOS・Linuxでは実行していません。
  • 展開後は更新時刻が変わる場合があります。
  • 同時にファイルが変更される状況や、ディスク容量不足は試験していません。

サイト全体の執筆・検証方針

自分で実行するためのサンプルファイル

コード、入力データ、実行手順が含まれています。展開して、まずREADME.txtを読んでください。

サンプルZIPをダウンロード

サンプルコード、ファイル名、入力キーは原文のままです。翻訳本文のコマンドと確認手順も併せて参照してください。

独自に作成した練習用資料 · 元のファイルを別に保管してから実行してください。

参考資料

説明と例は独自に作成しました。関連する動作や概念は、以下の公式資料で確認できます。