Python osモジュール:ファイルとディレクトリ操作ガイド
Updated on
設定ファイルを読み取ったり、出力を保存したり、データを整理したり、デプロイを自動化したりするすべてのPythonスクリプトは、ファイルシステムと対話する必要があります。しかし、ファイルパスはWindows、macOS、Linuxで異なる動作をします。ハードコードされた/home/user/dataパスはWindowsでは動作しません。+と/で文字列を手動で連結すると、二重スラッシュのバグやセパレーターの欠落につながります。そして適切なチェックがなければ、スクリプトが間違ったファイルを削除したり、ディレクトリがすでに存在する場合にクラッシュしたりする可能性があります。
Pythonのosモジュールはこれらの問題を解決します。オペレーティングシステムと連携するためのポータブルでクロスプラットフォームなインターフェースを提供します -- ディレクトリの作成、ファイルの一覧表示、環境変数の読み取り、パスの操作、ディレクトリツリーの走査が可能です。すべてのPythonインストールに同梱されており、pip installは不要で、プラットフォームの違いを自動的に処理します。
このガイドでは、osモジュールのすべての重要な関数を、ユースケース別に整理し、プロジェクトに直接コピーできる実用的な例とともに解説します。
現在の作業ディレクトリの取得
ファイルに対して何かを行う前に、スクリプトがどこで実行されているかを知る必要があります。os.getcwd()は現在の作業ディレクトリを絶対パスとして返します。
import os
# 現在の作業ディレクトリを取得
cwd = os.getcwd()
print(cwd) # e.g., /home/user/projects/myapp
# 作業ディレクトリを変更
os.chdir('/tmp')
print(os.getcwd()) # /tmp
# 元に戻す
os.chdir(cwd)相対パスを構築する場合や、一時的に変更した後で作業ディレクトリを復元する必要がある場合にos.getcwd()を使用します。
ディレクトリ操作
ディレクトリの作成
os.mkdir()は単一のディレクトリを作成します。ディレクトリがすでに存在する場合はFileExistsErrorを、親ディレクトリが存在しない場合はFileNotFoundErrorを発生させます。
import os
# 単一のディレクトリを作成
os.mkdir('output')
# 存在しない場合のみ作成
if not os.path.exists('output'):
os.mkdir('output')os.makedirs()はディレクトリを再帰的に作成します -- 不足しているすべての親ディレクトリを含めて。exist_ok=Trueパラメーターは、ディレクトリがすでに存在する場合のエラーを防ぎます。
import os
# ネストされたディレクトリを1回の呼び出しで作成
os.makedirs('data/raw/2026/january', exist_ok=True)
# exist_okなしの場合、'data'がすでに存在するとFileExistsErrorが発生
# os.makedirs('data/raw/2026/january') # エラーが発生する可能性ありディレクトリの内容を一覧表示
os.listdir()は、指定されたパス内のすべてのエントリ(ファイルとディレクトリ)のリストを返します。
import os
# 現在のディレクトリのすべてを一覧表示
entries = os.listdir('.')
print(entries) # ['main.py', 'data', 'output', 'README.md']
# 特定のディレクトリの内容を一覧表示
data_files = os.listdir('/var/log')
print(data_files)os.scandir()は、キャッシュされたファイル属性を持つDirEntryオブジェクトを返す、より効率的な代替手段です。名前とともにファイルメタデータが必要な場合に使用します。
import os
with os.scandir('.') as entries:
for entry in entries:
info = entry.stat()
print(f"{entry.name:30s} {'DIR' if entry.is_dir() else 'FILE':4s} {info.st_size} bytes")ディレクトリの削除
os.rmdir()は空のディレクトリを削除します。空でないディレクトリには、代わりにshutil.rmtree()を使用します。
import os
import shutil
# 空のディレクトリを削除
os.rmdir('output')
# ディレクトリとそのすべての内容を削除(注意して使用)
shutil.rmtree('data/raw/2026')ファイル操作
ファイルの削除
os.remove()(またはそのエイリアスos.unlink())は単一のファイルを削除します。ファイルが存在しない場合はFileNotFoundErrorを発生させます。
import os
# ファイルを削除
os.remove('temp_output.csv')
# 存在確認付きの安全な削除
filepath = 'temp_output.csv'
if os.path.exists(filepath):
os.remove(filepath)
print(f"{filepath}を削除しました")
else:
print(f"{filepath}が見つかりません")ファイルの名前変更と移動
os.rename()はファイルまたはディレクトリの名前を変更するか移動します。宛先がすでに存在する場合、動作はプラットフォームに依存します -- Unixでは上書きされる可能性がありますが、Windowsではエラーが発生する可能性があります。保証されたアトミック置換にはos.replace()を使用します。
import os
# ファイルの名前を変更
os.rename('old_report.csv', 'new_report.csv')
# ファイルを別のディレクトリに移動
os.rename('report.csv', 'archive/report_2026.csv')
# アトミック置換(すべてのプラットフォームで宛先を上書き)
os.replace('new_data.csv', 'data.csv')ファイル情報の取得
os.stat()はサイズ、パーミッション、タイムスタンプを含む詳細なファイルメタデータを返します。
import os
from datetime import datetime
info = os.stat('data.csv')
print(f"サイズ: {info.st_size} bytes")
print(f"更新日時: {datetime.fromtimestamp(info.st_mtime)}")
print(f"作成日時: {datetime.fromtimestamp(info.st_ctime)}")
print(f"パーミッション: {oct(info.st_mode)}")os.pathによるパス操作
os.pathサブモジュールは、日常的なファイルシステム作業のほとんどが行われる場所です。プラットフォーム間でのパスの構築、検証、分解を処理します。
パスを安全に構築する
パスを+で連結しないでください。オペレーティングシステムに関係なく、os.path.join()を使用してパスを正しく構築します。
import os
# 正しい方法:os.path.joinがセパレーターを処理
path = os.path.join('data', 'raw', 'sales.csv')
print(path) # Unixでは'data/raw/sales.csv'、Windowsでは'data\\raw\\sales.csv'
# 間違い:文字列連結は失敗する可能性がある
bad_path = 'data' + '/' + 'raw' + '/' + 'sales.csv' # Windowsで失敗存在とタイプの確認
import os
# パスが存在するか確認(ファイルまたはディレクトリ)
print(os.path.exists('/etc/hosts')) # True(Linux/macOSの場合)
# ファイルであることを確認
print(os.path.isfile('main.py')) # True
print(os.path.isfile('data')) # False(ディレクトリです)
# ディレクトリであることを確認
print(os.path.isdir('data')) # True
print(os.path.isdir('main.py')) # Falseパスの分解
手動で文字列を分割せずにファイルパスからコンポーネントを抽出します。
import os
filepath = '/home/user/projects/report_final.csv'
# ファイル名を取得
print(os.path.basename(filepath)) # 'report_final.csv'
# ディレクトリを取得
print(os.path.dirname(filepath)) # '/home/user/projects'
# ディレクトリとファイル名に分割
directory, filename = os.path.split(filepath)
print(directory) # '/home/user/projects'
print(filename) # 'report_final.csv'
# ファイル名と拡張子を分割
name, ext = os.path.splitext(filepath)
print(name) # '/home/user/projects/report_final'
print(ext) # '.csv'
# 相対パスから絶対パスを取得
print(os.path.abspath('data.csv')) # '/home/user/projects/data.csv'
# ユーザーのホームディレクトリを解決
print(os.path.expanduser('~/Documents')) # '/home/user/Documents'パス操作クイックリファレンス
| 関数 | 目的 | 出力例 |
|---|---|---|
os.path.join('a', 'b.txt') | パスの構築 | 'a/b.txt' |
os.path.exists(path) | パスが存在するか | True / False |
os.path.isfile(path) | ファイルか | True / False |
os.path.isdir(path) | ディレクトリか | True / False |
os.path.basename(path) | ファイル名のみ | 'report.csv' |
os.path.dirname(path) | ディレクトリのみ | '/home/user' |
os.path.splitext(path) | 名前と拡張子を分割 | ('report', '.csv') |
os.path.abspath(path) | 絶対パス | '/full/path/to/file' |
os.path.getsize(path) | ファイルサイズ(バイト) | 4096 |
os.path.expanduser('~') | ホームディレクトリ | '/home/user' |
環境変数
osモジュールはシステム環境変数への直接アクセスを提供します -- 設定、APIキー、デプロイ設定の読み取りに不可欠です。
import os
# 環境変数を読み取る(設定されていない場合はNoneを返す)
db_host = os.getenv('DATABASE_HOST')
print(db_host)
# デフォルト値付きで読み取る
db_port = os.getenv('DATABASE_PORT', '5432')
print(db_port) # DATABASE_PORTが設定されていない場合は'5432'
# os.environ辞書経由でアクセス(欠落している場合はKeyErrorを発生)
try:
secret = os.environ['API_SECRET']
except KeyError:
print("API_SECRETが設定されていません")
# 環境変数を設定(子プロセス用)
os.environ['APP_MODE'] = 'production'
# すべての環境変数を一覧表示
for key, value in os.environ.items():
print(f"{key}={value}")os.getenv()とos.environ[]の違いは重要です:getenvは変数が欠落している場合にNone(またはデフォルト値)を返しますが、os.environ[]はKeyErrorを発生させます。オプションの設定にはgetenvを、欠落時に大きなエラーを出すべき必須の設定にはos.environを使用します。
os.walkによるディレクトリツリーの走査
os.walk()はディレクトリツリーを再帰的に走査し、訪問する各ディレクトリに対して3タプル(dirpath, dirnames, filenames)を返します。
import os
# プロジェクトディレクトリを走査
for dirpath, dirnames, filenames in os.walk('/home/user/project'):
# 隠しディレクトリをスキップ
dirnames[:] = [d for d in dirnames if not d.startswith('.')]
print(f"\nディレクトリ: {dirpath}")
print(f" サブディレクトリ: {dirnames}")
print(f" ファイル: {filenames}")dirnames[:]のインプレース変更は、os.walkが入るサブディレクトリを制御します。これは.git、__pycache__、node_modulesディレクトリをスキップするための強力なパターンです。
ディレクトリの合計サイズを計算
import os
def get_directory_size(path):
total = 0
for dirpath, dirnames, filenames in os.walk(path):
for filename in filenames:
filepath = os.path.join(dirpath, filename)
# シンボリックリンクをスキップ
if not os.path.islink(filepath):
total += os.path.getsize(filepath)
return total
size_bytes = get_directory_size('/home/user/project')
size_mb = size_bytes / (1024 * 1024)
print(f"合計サイズ: {size_mb:.2f} MB")一般的なパターン
拡張子でファイルを検索
import os
def find_files(directory, extension):
"""指定された拡張子を持つすべてのファイルを再帰的に検索。"""
matches = []
for dirpath, dirnames, filenames in os.walk(directory):
for filename in filenames:
if filename.endswith(extension):
matches.append(os.path.join(dirpath, filename))
return matches
# すべてのPythonファイルを検索
python_files = find_files('/home/user/project', '.py')
for f in python_files:
print(f)
# すべてのCSVデータファイルを検索
csv_files = find_files('data', '.csv')
print(f"{len(csv_files)}個のCSVファイルが見つかりました")ネストされた出力構造の作成
import os
def setup_project_dirs(base_path):
"""標準的なプロジェクトディレクトリ構造を作成。"""
dirs = [
'data/raw',
'data/processed',
'data/output',
'logs',
'config',
'reports/figures',
]
for d in dirs:
full_path = os.path.join(base_path, d)
os.makedirs(full_path, exist_ok=True)
print(f"作成: {full_path}")
setup_project_dirs('my_project')一時ファイルによる安全なファイル操作
import os
import tempfile
# 自動削除される一時ファイルを作成
with tempfile.NamedTemporaryFile(mode='w', suffix='.csv', delete=False) as tmp:
tmp.write('col1,col2\n1,2\n3,4\n')
tmp_path = tmp.name
print(f"一時ファイル: {tmp_path}")
print(f"存在: {os.path.exists(tmp_path)}")
# クリーンアップ
os.remove(tmp_path)os.path vs pathlib:どちらを使うべきか?
Python 3.4はos.pathのオブジェクト指向の代替としてpathlibを導入しました。どちらも機能しますが、異なる強みがあります。
| 特徴 | os.path | pathlib |
|---|---|---|
| スタイル | 関数型(文字列ベース) | オブジェクト指向 |
| 利用可能 | Python 2以降 | Python 3.4以降 |
| パス連結 | os.path.join('a', 'b') | Path('a') / 'b' |
| 存在確認 | os.path.exists(p) | p.exists() |
| ファイル読み取り | open(os.path.join(d, f)) | Path(d, f).read_text() |
| Globパターン | import glob; glob.glob(...) | Path('.').glob('*.py') |
| 再帰的Glob | os.walk() + フィルター | Path('.').rglob('*.py') |
| ファイル拡張子 | os.path.splitext(f)[1] | p.suffix |
| ファイルステム | os.path.splitext(os.path.basename(f))[0] | p.stem |
| クロスプラットフォーム | はい | はい |
| サードパーティ互換性 | ユニバーサル | ほとんどのライブラリがPathオブジェクトを受け入れる |
os.pathを使うべき場合: レガシーなコードベース、Python 2をサポートする必要があるスクリプト、または文字列パスのみを受け入れるライブラリを使用する場合。
pathlibを使うべき場合: 新しいプロジェクト、よりクリーンな構文が必要な場合、または複数のパス操作をチェーンする場合。
# os.pathアプローチ
import os
config_path = os.path.join(os.path.expanduser('~'), '.config', 'myapp', 'settings.json')
if os.path.isfile(config_path):
with open(config_path) as f:
data = f.read()
# pathlibアプローチ
from pathlib import Path
config_path = Path.home() / '.config' / 'myapp' / 'settings.json'
if config_path.is_file():
data = config_path.read_text()どちらのアプローチも有効です。osモジュールは非推奨ではなく、プロセスレベルの操作、環境変数、低レベルのシステムコールの標準として残っています。pathlibは単にパス操作のためのより人間工学的なAPIを提供するだけです。
クロスプラットフォームの考慮事項
osモジュールは現在のオペレーティングシステムに自動的に適応しますが、知っておく価値のある詳細があります。
import os
# os.sepはプラットフォームのパスセパレーター
print(os.sep) # Unixでは'/'、Windowsでは'\\'
# os.linesepはプラットフォームの改行コード
print(repr(os.linesep)) # Unixでは'\n'、Windowsでは'\r\n'
# os.nameはOS系列を識別
print(os.name) # Linux/macOSでは'posix'、Windowsでは'nt'
# os.path.joinはセパレーターを自動的に処理
path = os.path.join('data', 'output', 'results.csv')
# Unixでは'data/output/results.csv'
# Windowsでは'data\\output\\results.csv'クロスプラットフォームスクリプトの重要なルール:
/や\\による文字列連結の代わりに、常にos.path.join()を使用する。/home/usernameをハードコードする代わりに、os.path.expanduser('~')を使用する。\nをハードコードする代わりに、os.linesepを使用するか、テキストモードでファイルを開く(改行を処理する)。- スクリプトを共有する場合は、両方のプラットフォームでパスロジックをテストする。
RunCellでファイルシステムタスクを自動化
Jupyterノートブックでファイルシステム操作を行う場合 -- データセットの整理、プロジェクト構造のセットアップ、ファイルツリーの監査 -- RunCell (opens in a new tab)はノートブック環境の上にAIエージェントレイヤーを追加します。やりたいことを説明するだけで(「このディレクトリツリーで100MB以上のCSVファイルをすべて見つけてサイズ順にリストして」)、RunCellがosモジュールのコードを生成して実行し、繰り返しのファイル管理タスクを高速化します。
FAQ
Pythonのosモジュールとは何ですか?
osモジュールはPythonの標準ライブラリの一部です。ファイルとディレクトリの操作、パスの処理、環境変数へのアクセス、プロセス管理など、オペレーティングシステムとの対話のための関数を提供します。import osでインポートします -- インストールは不要です。
os.path.joinと文字列連結の違いは何ですか?
os.path.join()は現在のオペレーティングシステムに対して正しいパスセパレーターを自動的に使用します(Unixでは/、Windowsでは\)。+による文字列連結ではセパレーターを手動で挿入する必要があり、異なるプラットフォームでコードを実行するとバグの原因になります。常にos.path.join()を使用してください。
ディレクトリ内のすべてのファイルを再帰的にリストするにはどうすればよいですか?
os.walk()を使用してディレクトリツリーを走査します。各ディレクトリに対して(dirpath, dirnames, filenames)タプルを返します。os.path.join(dirpath, filename)と組み合わせて、各ファイルの完全なパスを構築します。
os.pathとpathlibのどちらを使うべきですか?
新しいPython 3プロジェクトでは、pathlibがそのオブジェクト指向APIにより、よりクリーンで読みやすい構文を提供します。ただし、osとos.pathは非推奨ではなく、環境変数(os.environ)、プロセス操作、レガシーコードベースには依然として正しい選択です。多くのプロジェクトは両方を使用しています。
Pythonでファイルやディレクトリを安全に削除するにはどうすればよいですか?
ファイルの削除にはos.remove(path)を、空のディレクトリの削除にはos.rmdir(path)を使用します。常に先にos.path.exists(path)を確認するか、FileNotFoundErrorを処理するためにtry/exceptブロックで呼び出しをラップします。空でないディレクトリにはshutil.rmtree(path)を使用します。
まとめ
Pythonのosモジュールは、スクリプトが実行するすべてのファイルシステム操作の基盤です。os.path.join()はプラットフォーム間で安全にパスを構築します。os.makedirs()は1回の呼び出しでネストされたディレクトリを作成します。os.walk()はディレクトリツリー全体を走査します。os.environとos.getenv()はシークレットをハードコードせずに設定を処理します。そしてos.stat()は詳細なファイルメタデータを提供します。
パス重視のコードでは、よりクリーンな構文のためにosとpathlibを組み合わせることを検討してください。しかしosモジュールは不可欠であり続けます -- Pythonでオペレーティングシステムと対話する標準的な方法であり、すべてのPython開発者がそのコア関数を知っておくべきです。