Python のファイル操作モジュール 総まとめ

## はじめに

プログラミングにおいて、ファイル操作は最も基本的かつ重要な機能の一つです。
データの保存、設定ファイルの読み込みなど、多くのプログラムでファイル操作が必要不可欠です。

Python には、目的に応じて使い分けられる複数のファイル操作モジュールが用意されています：

- 基本的な読み書き: `open()`関数
- ファイルシステム操作: `os`モジュール
- モダンなパス操作: `pathlib`モジュール
- 高レベルなファイル操作: `shutil`モジュール

本記事では、これらのモジュールの特徴と使用方法を、基本から応用まで段階的に解説します。

## open() 関数によるファイル操作の基礎

open() 関数を使用することで、ファイルを開いて読み込んだり、ファイルに文字列を書き込んだりできます。

### 基本的な読み書き

```python
# テキストファイルの書き込み
with open('sample.txt', 'w', encoding='utf-8') as f:
    f.write('Hello, World!\n')
    f.writelines(['First line\n', 'Second line\n'])

# テキストファイルの読み込み
with open('sample.txt', 'r', encoding='utf-8') as f:
    # ファイル全体を1つの文字列として読み込み
    content = f.read()

    # ファイルを最初から読み直す
    f.seek(0)

    # 1行ずつ読み込み
    for line in f:
        print(line.strip())
```

### ファイルモードと使い分け

```python
# 書き込み専用 ('w') - ファイルを新規作成または上書き
with open("file.txt", "w") as f:
    f.write("new content")

# 読み込み専用 ('r')
with open("file.txt", "r") as f:
    content = f.read()
    print(content)

# 追記モード ('a')
with open("log.txt", "a") as f:
    f.write("新しいログエントリ\n")

# バイナリモード ('rb', 'wb')
with open("image.png", "rb") as f:
    binary_data = f.read()
    print("{0:02x}".format(binary_data[0]))  # バイナリの先頭 1 バイトを出力
```

### エラーハンドリング

```python
try:
    with open('nonexistent.txt', 'r') as f:
        content = f.read()
except FileNotFoundError:
    print('ファイルが存在しません')
except PermissionError:
    print('ファイルにアクセスする権限がありません')
```

## os モジュールによるファイルシステム操作

os モジュールを使用することで、実行環境の OS の差をあまり意識することなくファイルやディレクトリの簡易的な操作ができます。

### 基本的なファイル操作

```python
import os

# ファイルの存在確認
if os.path.exists("old.txt"):
    print("ファイルが存在します")

# ファイル操作
os.rename("old.txt", "new.txt")  # ファイル名変更
os.remove("new.txt")  # ファイル削除
os.chmod("file.txt", 0o755)  # 権限変更

# ファイル情報の取得
size = os.path.getsize("file.txt")
mtime = os.path.getmtime("file.txt")  # 最終更新時刻
print(f"size = {size}, mtime = {mtime}")
```

### ディレクトリ操作

```python
import os

# カレントディレクトリの取得と変更
current_dir = os.getcwd()
os.chdir("path/to/directory")

# ディレクトリ作成
os.mkdir("new_directory")  # 単一ディレクトリ
os.makedirs("path/to/deep/dir")  # 途中のディレクトリも作成

# ディレクトリ内のディレクトリやファイルの一覧取得
files = os.listdir(".")
print(files)
```

### パス操作

```python
import os

# パスの結合
full_path = os.path.join("directory", "subdirectory", "file.txt")
print(full_path)  # directory/subdirectory/file.txt

# パスの分割
dir_name = os.path.dirname("/path/to/file.txt")
print(dir_name)  # /path/to

base_name = os.path.basename("/path/to/file.txt")
print(base_name)  # file.txt

root, ext = os.path.splitext("file.txt")
print(f"root = {root}, ext = {ext}")  # root = file, ext = .txt
```

## pathlib モジュールによるモダンなパス操作

pathlib モジュール を使用することで、os モジュールよりもスマートに様々な操作が実現できます。

### Path オブジェクトの基本

```python
from pathlib import Path

# パスオブジェクトの作成
current_file = Path("file.txt")
print(current_file)

project_dir = Path("/path/to/project")
print(project_dir)

# 特別なパス
current_dir = Path.cwd()
print(current_dir)

home_dir = Path.home()
print(home_dir)
```

### パス操作とプロパティ

```python
from pathlib import Path

path = Path("/path/to/file.txt")

# パスの各部分へのアクセス
print(path.parent)  # 親ディレクトリ
print(path.name)  # ファイル名
print(path.stem)  # 拡張子を除いたファイル名
print(path.suffix)  # 拡張子

# パスの結合 (Path オブジェクトにより / 演算子がオーバーロードされている)
new_path = path.parent / "another_file.txt"
print(new_path)
```

### ファイル操作

```python
from pathlib import Path

# Pathオブジェクトの作成
file_path = Path("example.txt")

# ファイルの読み書き
content = file_path.read_text(encoding="utf-8")
file_path.write_text("Hello, World!", encoding="utf-8")

# ファイルの存在確認と種類
if file_path.exists():
    print(f"Is file: {file_path.is_file()}")
    print(f"Is directory: {file_path.is_dir()}")

# ファイル検索
# カレントディレクトリのPathオブジェクトを作成
current_dir = Path(".")
# 再帰的にPythonファイルを検索
for python_file in current_dir.glob("**/*.py"):
    print(python_file)
```

## shutil モジュールによる高レベルなファイル操作

シェルで実現できるような操作を実施したいとき、shutil モジュールを使用すれば可能かもしれません。

### ファイルのコピーと移動

```python
import shutil

# ファイルのコピー
shutil.copy("source.txt", "dest.txt")  # ファイルをコピー
shutil.copy2("source.txt", "dest.txt")  # メタデータも含めてコピー

# ディレクトリのコピー
shutil.copytree("src_dir", "dst_dir")  # ディレクトリ全体をコピー
shutil.copytree("src_dir", "dst_dir", dirs_exist_ok=True)  # 上書きコピー

# ファイル・ディレクトリの移動
shutil.move("source.txt", "dest/file.txt")
```

### ディレクトリツリーの操作

```python
from pathlib import Path
import shutil
import time

# ディレクトリの削除
shutil.rmtree("dest")  # 中身ごと削除

# ディレクトリ内の古いファイルの削除
def remove_old_files(directory, days):
    path = Path(directory)
    threshold = time.time() - (days * 86400)
    for item in path.glob("**/*"):
        if item.is_file() and item.stat().st_mtime < threshold:
            item.unlink()
```

### アーカイブ操作

```python
import shutil

# アーカイブの作成
shutil.make_archive("archive_name", "zip", "directory_to_compress")

# アーカイブの展開
shutil.unpack_archive("archive_name.zip", "extract_dir")
```

## まとめ

### モジュールの使い分け

1. **基本的なファイル読み書き**

   - `open()`: シンプルなテキストファイルの読み書き
   - エンコーディングの指定が可能
   - with ステートメントでの使用推奨

2. **ファイルシステム操作**

   - `os`: システムレベルのファイル操作
   - パス操作の基本機能
   - 下位レベルの操作が必要な場合に使用

3. **モダンなパス操作**

   - `pathlib`: オブジェクト指向的なパス操作
   - クロスプラットフォームでの一貫した操作
   - 下位レベルの操作が不要であれば積極的に利用したい

4. **高レベルなファイル操作**
   - `shutil`: 複雑なファイル操作
   - ディレクトリツリーの操作
   - ファイルのコピー、移動、削除の高レベル関数

これらのモジュールを適切に組み合わせることで、効率的で安全なファイル操作が実現できます。