複数のCSVを結合し、元のファイル名を残す
列構成が同じCSVを順番に結合し、source_file列を追加します。カンマを含む品目名、列の欠落、既存の出力も、小さなデータで確認します。
サブフォルダーまで調べ、ファイルのパス、拡張子、サイズ、更新時刻を表に記録します。小さなサンプルファイル4個から始め、元のファイルと既存の結果を保管します。
この翻訳はAIで作成しました。コード、単位、数値は原文と併せて確認してください。各言語のネイティブ話者による校閲は、まだ完了していません。 한국어
対象読者フォルダー内の文書数や保存場所を手作業で整理してきたPython初心者
フォルダーが作成されただけでは、この作業は完了ではありません。CSVに元の四つのファイルが一回ずつ入り、表示されたバイト数の合計が63で、元の内容が変わっていないことが必要です。まず同梱の資料でこの条件を確認してから、自分の業務フォルダーに広げてください。
python example.pyコードは、ターミナルの現在のフォルダーではなく、example.pyの保存場所を基準にします。BASEの下にあるsample_filesだけを調べるため、サンプルフォルダー全体を移動しても、相対的な配置が同じなら動作します。outputsは調査対象の外に置き、結果のCSVが再び入力一覧に混ざらないようにしています。
| 列 | 意味 | 読むときの確認点 |
|---|---|---|
| relative_path | sample_filesを基準とする相対パス | 同じ名前でも、フォルダーが異なれば区別できます。 |
| extension | 最後の拡張子を小文字で表示 | 拡張子がない場合は(없음)と表示され、tar.gzの場合は.gzになります。 |
| size_bytes | ファイルサイズをバイト単位の整数で表示 | 0は空のファイルを示し、欠落を意味しません。 |
| modified_utc | UTCで表したファイルの更新時刻 | 末尾の+00:00はUTCを示し、韓国の現地時刻とは異なります。 |
relative_pathは、OSが異なっても読みやすいようにスラッシュで表示します。結果はこのパスを基準に並べ替えます。ファイル探索の内部的な順序に依存しないため、同じ入力の行順を比較しやすくなります。
collect_filesは情報の収集、mainは新しいCSVへの書き込みを担当します。入力の確認が終わるまでoutputsは作成しません。読み取れないフォルダーやリンクが見つかった場合は、一部だけの一覧を成功した結果として保存せず、処理を停止します。
"""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フォルダー自体の存在を確認します。
| relative_path | extension | size_bytes |
|---|---|---|
| docs/agenda.txt | .txt | 15 |
| empty.txt | .txt | 0 |
| readme.txt | .txt | 17 |
| reports/sales.csv | .csv | 31 |
上の表の合計は15 + 0 + 17 + 31 = 63バイトです。ターミナルにも「완료: 4개 파일, 합계 63바이트」という完了メッセージが表示されます。CSVの先頭行は列名なので、スプレッドシートではヘッダーを含めて五行になります。empty.txtを数え忘れないようにしてください。
失敗条件も、正常な設計の一部です。再実行できないからといって、出力を拒否するコードを削除しないでください。前の結果が必要なら、outputsを日付入りの別名に変更して保管してから再実行するか、ZIPを新しいフォルダーに展開して新たに試します。
最初から業務フォルダー全体を対象にせず、代表的なファイルをいくつかsample_filesのコピーに入れてみてください。韓国語や空白を含むファイル名も、パスオブジェクトで扱います。ただし、別の場所につながるシンボリックリンクやリンクされたディレクトリは対象外なので、通常のファイルだけを含む小さなコピーが適しています。
入力フォルダーが空の場合は、ヘッダーだけのCSVが生成され、ファイル数は0と表示されます。これは、フォルダーが存在せず処理が止まる場合とは異なります。空のフォルダーも業務上の正常な状態になり得るため、結果を解釈するときは区別してください。
| 症状 | 考えられる原因 | 次に行うこと |
|---|---|---|
| pythonコマンドが見つからない | 実行環境のインストールまたはパス設定の問題 | まずpython --versionを確認し、Windowsではpyを試します。 |
| sample_filesが実際のフォルダーではない | フォルダーがない、またはリンクを使っている | ZIP全体を展開したか確認し、実際のフォルダーを復元します。 |
| outputsがすでに存在する | 前回の実行結果が残っている | 既存の結果を別の場所に保管してから、再実行します。 |
| 韓国語の文字が正しく表示されない | 開くプログラムによる文字コードの解釈に問題がある | CSVのインポート時にUTF-8を指定し、元のファイルは変更しません。 |
| 読み取り権限のエラー | アクセスできないフォルダー、またはロックされたパス | まずアクセス可能な練習用コピーに対象を絞ります。 |
この結果は、実行中に確認したファイル情報です。内容が同じかを比較する重複検査でも、復元可能なバックアップでもありません。ファイルサイズが同じ二つの文書でも、内容は異なることがあります。ハッシュ比較が必要な場合は、その目的と専用の列を別途追加する必要があります。
この入門例では、調査中に別のプログラムがファイル名や内容を変える場合、ネットワークドライブの遅延、非常に多くのファイルを一度にメモリへ集める場合は扱いません。出力中にディスクへの書き込みが失敗すると、不完全なoutputsが残る場合があります。完了メッセージと結果の行数を併せて確認してください。
2026-09-19 · Windows 11 · CPython 3.12.14 · 追加パッケージなし · 配布版の一時コピーで実行
コード、入力データ、実行手順が含まれています。展開して、まずREADME.txtを読んでください。
サンプルZIPをダウンロードサンプルコード、ファイル名、入力キーは原文のままです。翻訳本文のコマンドと確認手順も併せて参照してください。
独自に作成した練習用資料 · 元のファイルを別に保管してから実行してください。
説明と例は独自に作成しました。関連する動作や概念は、以下の公式資料で確認できます。