Pythonファイル操作完全攻略【読み書き・パス操作を徹底マスター】
ファイル操作は、データの永続化、設定ファイルの管理、ログ記録など、プログラム開発において不可欠な技術です。Pythonでは豊富な標準ライブラリにより、テキストファイル、バイナリファイル、CSVファイルなど様々な形式のファイルを効率的に操作できます。本記事では、ファイル操作の基本から応用まで、実用的なサンプルコードとともに徹底解説します。
目次
ファイル操作の基本概念
ファイル操作の主な用途
- データ保存: アプリケーションデータの永続化
- 設定管理: 設定ファイルの読み書き
- ログ記録: エラーログ、アクセスログの出力
- データ分析: CSV、JSONファイルの処理
- バックアップ: ファイルのコピー、移動
ファイルモードの種類
| モード | 説明 | 用途 |
|---|---|---|
| ‘r’ | 読み取り専用 | ファイル読み込み |
| ‘w’ | 書き込み専用(上書き) | ファイル作成・上書き |
| ‘a’ | 追記モード | ログファイルへの追記 |
| ‘x’ | 排他的作成 | 新規ファイル作成 |
| ‘b’ | バイナリモード | 画像、音声ファイル |
| ‘t’ | テキストモード | テキストファイル(デフォルト) |
基本的なファイル読み込み
open()関数の基本
# 基本的なファイル読み込み
with open('sample.txt', 'r', encoding='utf-8') as file:
content = file.read()
print(content)
行ごとの読み込み
# 1行ずつ読み込み
with open('data.txt', 'r', encoding='utf-8') as file:
for line_num, line in enumerate(file, 1):
print(f"{line_num}: {line.strip()}")
readlines()とreadline()
# 全行をリストで取得
with open('sample.txt', 'r', encoding='utf-8') as file:
lines = file.readlines()
print(f"行数: {len(lines)}")
# 1行ずつ読み込み
with open('sample.txt', 'r', encoding='utf-8') as file:
first_line = file.readline().strip()
second_line = file.readline().strip()
print(f"1行目: {first_line}")
print(f"2行目: {second_line}")
ファイル書き込み
基本的な書き込み
# ファイルに書き込み(上書き)
with open('output.txt', 'w', encoding='utf-8') as file:
file.write("Hello, World!\n")
file.write("Pythonファイル操作\n")
# 複数行の書き込み
lines = ["1行目\n", "2行目\n", "3行目\n"]
with open('multi_lines.txt', 'w', encoding='utf-8') as file:
file.writelines(lines)
追記モード
# ファイルに追記
with open('log.txt', 'a', encoding='utf-8') as file:
file.write("新しいログエントリ\n")
# タイムスタンプ付きログ
from datetime import datetime
with open('app.log', 'a', encoding='utf-8') as file:
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
file.write(f"[{timestamp}] アプリケーション開始\n")
print()関数でのファイル出力
# print()関数を使ったファイル出力
with open('print_output.txt', 'w', encoding='utf-8') as file:
print("Hello", "World", file=file)
print(f"計算結果: {2 + 3}", file=file)
print("=" * 20, file=file)
pathlib モジュールの活用
パスの基本操作
from pathlib import Path
# パスオブジェクトの作成
file_path = Path('data/sample.txt')
print(file_path.name) # sample.txt
print(file_path.suffix) # .txt
print(file_path.parent) # data
print(file_path.stem) # sample
ディレクトリとファイルの存在確認
from pathlib import Path
path = Path('example.txt')
print(f"ファイル存在: {path.exists()}")
print(f"ファイル: {path.is_file()}")
print(f"ディレクトリ: {path.is_dir()}")
# ディレクトリ作成
output_dir = Path('output')
output_dir.mkdir(exist_ok=True) # 既存でもエラーにしない
glob パターンでのファイル検索
from pathlib import Path
# カレントディレクトリの.txtファイルを取得
txt_files = list(Path('.').glob('*.txt'))
print(f"テキストファイル数: {len(txt_files)}")
# 再帰的検索
all_py_files = list(Path('.').rglob('*.py'))
for py_file in all_py_files[:5]: # 最初の5個を表示
print(py_file)
os と os.path モジュール
ファイル・ディレクトリ操作
import os
# カレントディレクトリの取得・変更
current_dir = os.getcwd()
print(f"現在のディレクトリ: {current_dir}")
# ディレクトリ内容の取得
files = os.listdir('.')
print(f"ファイル数: {len(files)}")
# ディレクトリ作成
os.makedirs('new_folder/subfolder', exist_ok=True)
パス操作
import os.path
# パスの結合
file_path = os.path.join('data', 'files', 'sample.txt')
print(file_path)
# パス情報の取得
print(f"ディレクトリ: {os.path.dirname(file_path)}")
print(f"ファイル名: {os.path.basename(file_path)}")
print(f"拡張子: {os.path.splitext(file_path)[1]}")
# ファイル存在確認
if os.path.exists('config.txt'):
size = os.path.getsize('config.txt')
print(f"ファイルサイズ: {size} bytes")
CSVファイルの操作
CSV読み込み
import csv
# 基本的なCSV読み込み
with open('data.csv', 'r', encoding='utf-8') as file:
reader = csv.reader(file)
for row in reader:
print(row)
# 辞書形式でのCSV読み込み
with open('employees.csv', 'r', encoding='utf-8') as file:
reader = csv.DictReader(file)
for row in reader:
print(f"{row['name']}: {row['age']}歳")
CSV書き込み
import csv
# 基本的なCSV書き込み
data = [['名前', '年齢', '職業'], ['田中', '30', 'エンジニア'], ['佐藤', '25', 'デザイナー']]
with open('output.csv', 'w', newline='', encoding='utf-8') as file:
writer = csv.writer(file)
writer.writerows(data)
# 辞書データのCSV書き込み
employees = [
{'name': '田中', 'age': 30, 'job': 'エンジニア'},
{'name': '佐藤', 'age': 25, 'job': 'デザイナー'}
]
with open('employees_dict.csv', 'w', newline='', encoding='utf-8') as file:
writer = csv.DictWriter(file, fieldnames=['name', 'age', 'job'])
writer.writeheader()
writer.writerows(employees)
バイナリファイルの操作
画像ファイルのコピー
# バイナリファイルのコピー
def copy_binary_file(src, dst):
with open(src, 'rb') as src_file:
with open(dst, 'wb') as dst_file:
dst_file.write(src_file.read())
# 使用例
# copy_binary_file('image.jpg', 'image_copy.jpg')
ファイルサイズ制限付き読み込み
def read_large_file(filename, chunk_size=1024):
"""大きなファイルをチャンクごとに読み込み"""
with open(filename, 'rb') as file:
while True:
chunk = file.read(chunk_size)
if not chunk:
break
yield chunk
# 使用例
# for chunk in read_large_file('large_file.bin'):
# process_chunk(chunk) # チャンクごとに処理
一時ファイルの操作
tempfile モジュール
import tempfile
import os
# 一時ファイルの作成
with tempfile.NamedTemporaryFile(mode='w', delete=False, encoding='utf-8') as temp_file:
temp_file.write("一時的なデータ")
temp_name = temp_file.name
print(f"一時ファイル: {temp_name}")
# 一時ファイルの削除
os.unlink(temp_name)
# 一時ディレクトリ
with tempfile.TemporaryDirectory() as temp_dir:
temp_file_path = os.path.join(temp_dir, 'temp.txt')
with open(temp_file_path, 'w') as f:
f.write("一時ファイル内容")
print(f"一時ディレクトリ: {temp_dir}")
# with文を出ると自動的に削除される
ファイル情報の取得
ファイル属性の取得
import os
import stat
from datetime import datetime
def get_file_info(filename):
if not os.path.exists(filename):
return None
file_stat = os.stat(filename)
return {
'size': file_stat.st_size,
'modified': datetime.fromtimestamp(file_stat.st_mtime),
'created': datetime.fromtimestamp(file_stat.st_ctime),
'permissions': stat.filemode(file_stat.st_mode)
}
# 使用例
info = get_file_info('sample.txt')
if info:
print(f"サイズ: {info['size']} bytes")
print(f"更新日時: {info['modified']}")
print(f"権限: {info['permissions']}")
ディレクトリサイズの計算
import os
def get_directory_size(directory):
total_size = 0
for dirpath, dirnames, filenames in os.walk(directory):
for filename in filenames:
file_path = os.path.join(dirpath, filename)
try:
total_size += os.path.getsize(file_path)
except OSError:
pass # アクセスできないファイルをスキップ
return total_size
# 使用例
# size = get_directory_size('.')
# print(f"ディレクトリサイズ: {size / 1024 / 1024:.2f} MB")
エラーハンドリング
ファイル操作の例外処理
def safe_file_read(filename):
try:
with open(filename, 'r', encoding='utf-8') as file:
return file.read()
except FileNotFoundError:
print(f"ファイルが見つかりません: {filename}")
except PermissionError:
print(f"ファイルアクセス権限がありません: {filename}")
except UnicodeDecodeError:
print(f"文字エンコーディングエラー: {filename}")
except Exception as e:
print(f"予期しないエラー: {e}")
return None
# 使用例
content = safe_file_read('nonexistent.txt')
if content:
print(content)
ロバストなファイル書き込み
import os
import tempfile
def safe_file_write(filename, content):
"""原子的な書き込み操作"""
temp_file = None
try:
# 一時ファイルに書き込み
with tempfile.NamedTemporaryFile(mode='w', delete=False,
dir=os.path.dirname(filename),
encoding='utf-8') as temp_file:
temp_file.write(content)
temp_name = temp_file.name
# 原子的な置換
os.replace(temp_name, filename)
return True
except Exception as e:
print(f"書き込みエラー: {e}")
if temp_file and os.path.exists(temp_name):
os.unlink(temp_name)
return False
# 使用例
success = safe_file_write('important.txt', "重要なデータ")
print(f"書き込み{'成功' if success else '失敗'}")
ファイル操作の実用例
ログローテーション
import os
from datetime import datetime
class SimpleLogger:
def __init__(self, log_file, max_size=1024*1024): # 1MB
self.log_file = log_file
self.max_size = max_size
def log(self, message):
# ファイルサイズチェック
if os.path.exists(self.log_file) and os.path.getsize(self.log_file) > self.max_size:
self._rotate_log()
# ログ書き込み
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
with open(self.log_file, 'a', encoding='utf-8') as file:
file.write(f"[{timestamp}] {message}\n")
def _rotate_log(self):
backup_name = f"{self.log_file}.backup"
if os.path.exists(backup_name):
os.remove(backup_name)
os.rename(self.log_file, backup_name)
# 使用例
logger = SimpleLogger('app.log')
logger.log("アプリケーション開始")
logger.log("データ処理完了")
設定ファイル管理
import json
import os
class ConfigManager:
def __init__(self, config_file='config.json'):
self.config_file = config_file
self.config = self._load_config()
def _load_config(self):
if os.path.exists(self.config_file):
try:
with open(self.config_file, 'r', encoding='utf-8') as file:
return json.load(file)
except json.JSONDecodeError:
print("設定ファイルの形式が不正です")
# デフォルト設定
return {
'database': {'host': 'localhost', 'port': 5432},
'debug': False,
'log_level': 'INFO'
}
def get(self, key, default=None):
return self.config.get(key, default)
def set(self, key, value):
self.config[key] = value
self._save_config()
def _save_config(self):
with open(self.config_file, 'w', encoding='utf-8') as file:
json.dump(self.config, file, ensure_ascii=False, indent=2)
# 使用例
config = ConfigManager()
print(f"データベースホスト: {config.get('database', {}).get('host')}")
config.set('last_updated', '2024-01-01')
ファイル同期・バックアップ
import os
import shutil
from pathlib import Path
def backup_files(source_dir, backup_dir, extensions=None):
"""指定した拡張子のファイルをバックアップ"""
source_path = Path(source_dir)
backup_path = Path(backup_dir)
# バックアップディレクトリ作成
backup_path.mkdir(exist_ok=True)
count = 0
for file_path in source_path.rglob('*'):
if file_path.is_file():
# 拡張子フィルタ
if extensions and file_path.suffix.lower() not in extensions:
continue
# 相対パスを維持してコピー
relative_path = file_path.relative_to(source_path)
dest_path = backup_path / relative_path
dest_path.parent.mkdir(parents=True, exist_ok=True)
shutil.copy2(file_path, dest_path)
count += 1
return count
# 使用例
# backed_up = backup_files('.', 'backup', ['.py', '.txt'])
# print(f"バックアップ完了: {backed_up}ファイル")
パフォーマンス最適化
バッファサイズの最適化
def efficient_file_copy(src, dst, buffer_size=65536): # 64KB
"""効率的なファイルコピー"""
with open(src, 'rb') as src_file:
with open(dst, 'wb') as dst_file:
while True:
chunk = src_file.read(buffer_size)
if not chunk:
break
dst_file.write(chunk)
# バッファサイズによる性能比較
import time
def benchmark_copy(src, dst, buffer_sizes):
for buffer_size in buffer_sizes:
start = time.time()
efficient_file_copy(src, f"{dst}_{buffer_size}", buffer_size)
elapsed = time.time() - start
print(f"バッファサイズ {buffer_size}: {elapsed:.3f}秒")
# 使用例(大きなファイルで実行)
# benchmark_copy('large_file.bin', 'copy', [1024, 8192, 65536])
メモリ効率的な大容量ファイル処理
def process_large_text_file(filename, process_func):
"""大容量テキストファイルの行ごと処理"""
line_count = 0
with open(filename, 'r', encoding='utf-8') as file:
for line in file:
process_func(line.strip())
line_count += 1
if line_count % 10000 == 0:
print(f"処理済み: {line_count}行")
return line_count
# 使用例
def count_words(line):
return len(line.split())
# total_lines = process_large_text_file('huge_file.txt', count_words)
まとめ
Pythonでのファイル操作は、標準ライブラリの豊富な機能により様々なニーズに対応できます。適切な手法を選択することで、効率的で安全なファイル処理システムを構築できます。
重要なポイント:
- with文を使った安全なファイル操作
- pathlibでモダンなパス操作
- 適切なエンコーディング指定(utf-8推奨)
- 例外処理による堅牢なエラーハンドリング
- チャンク読み込みで大容量ファイルに対応
- 原子的操作で重要データの安全性確保
用途別の最適解:
- テキストファイル: open() + with文
- CSVファイル: csvモジュール
- 設定ファイル: json/configparserモジュール
- 大容量ファイル: チャンク処理
- バイナリファイル: ‘rb’/’wb’モード
本記事のサンプルコードを参考に、あなたのプロジェクトに最適なファイル操作を実装してください。適切なエラーハンドリングとパフォーマンス最適化により、実用的なシステムを構築できます。
参考文献
- Python公式ドキュメント – ファイルとディレクトリへのアクセス
- pathlib公式ドキュメント
- csv モジュール公式ドキュメント
- tempfile モジュール公式ドキュメント
■らくらくPython塾 – 読むだけでマスター
■プロンプトだけでオリジナルアプリを開発・公開してみた!!
■AI時代の第一歩!「AI駆動開発コース」はじめました!
テックジム東京本校で先行開始。
■テックジム東京本校
「武田塾」のプログラミング版といえば「テックジム」。
講義動画なし、教科書なし。「進捗管理とコーチング」で効率学習。
より早く、より安く、しかも対面型のプログラミングスクールです。
<短期講習>5日で5万円の「Pythonミニキャンプ」開催中。
<月1開催>放送作家による映像ディレクター養成講座
<オンライン無料>ゼロから始めるPython爆速講座


