Pythonでファイル・ディレクトリを移動する方法(shutil.move完全ガイド)

Pythonでファイルやディレクトリを移動する際に使用するshutil.move()の使い方を、実践的なサンプルコードと共に詳しく解説します。

基本的なファイル移動:shutil.move()

ファイルの移動

import shutil

# ファイルを別のディレクトリに移動
shutil.move('sample.txt', 'documents/sample.txt')

ファイル名変更を伴う移動

import shutil

# 移動と同時にファイル名も変更
shutil.move('old_name.txt', 'new_folder/new_name.txt')

ディレクトリの移動

ディレクトリ全体の移動

import shutil

# ディレクトリを丸ごと移動
shutil.move('source_folder', 'destination/source_folder')

存在しない移動先ディレクトリの作成

import os
import shutil

def safe_move(src, dst):
    # 移動先ディレクトリが存在しない場合は作成
    dst_dir = os.path.dirname(dst)
    if dst_dir and not os.path.exists(dst_dir):
        os.makedirs(dst_dir)
    
    shutil.move(src, dst)
    return f"'{src}' を '{dst}' に移動しました"

# 使用例
print(safe_move('file.txt', 'deep/nested/folder/file.txt'))

エラーハンドリングを含む安全な移動

基本的なエラーハンドリング

import shutil
import os

def move_with_error_handling(src, dst):
    try:
        if not os.path.exists(src):
            return f"エラー: '{src}' が存在しません"
        
        shutil.move(src, dst)
        return f"移動完了: '{src}' → '{dst}'"
    
    except PermissionError:
        return "エラー: 権限がありません"
    except shutil.Error as e:
        return f"移動エラー: {e}"
    except Exception as e:
        return f"予期しないエラー: {e}"

# 使用例
print(move_with_error_handling('test.txt', 'backup/test.txt'))

同名ファイル対応の移動

import os
import shutil

def move_with_rename(src, dst):
    if os.path.exists(dst):
        base, ext = os.path.splitext(dst)
        counter = 1
        while os.path.exists(f"{base}_{counter}{ext}"):
            counter += 1
        dst = f"{base}_{counter}{ext}"
    
    shutil.move(src, dst)
    return dst

# 使用例
new_path = move_with_rename('file.txt', 'backup/file.txt')
print(f"移動先: {new_path}")

パターン指定での一括移動

glob を使った複数ファイル移動

import glob
import shutil
import os

def move_files_by_pattern(pattern, destination):
    # 移動先ディレクトリを作成
    os.makedirs(destination, exist_ok=True)
    
    files = glob.glob(pattern)
    moved_files = []
    
    for file in files:
        filename = os.path.basename(file)
        dst = os.path.join(destination, filename)
        shutil.move(file, dst)
        moved_files.append(filename)
    
    return moved_files

# 使用例:すべての.txtファイルをbackupフォルダに移動
moved = move_files_by_pattern('*.txt', 'backup')
print(f"移動したファイル: {moved}")

条件指定での移動

import os
import shutil
import time

def move_old_files(source_dir, dest_dir, days_old=30):
    os.makedirs(dest_dir, exist_ok=True)
    cutoff_time = time.time() - (days_old * 24 * 60 * 60)
    moved_count = 0
    
    for filename in os.listdir(source_dir):
        filepath = os.path.join(source_dir, filename)
        
        if os.path.isfile(filepath):
            if os.path.getmtime(filepath) < cutoff_time:
                dst = os.path.join(dest_dir, filename)
                shutil.move(filepath, dst)
                moved_count += 1
    
    return moved_count

# 使用例:30日以上古いファイルを移動
count = move_old_files('current', 'archive', 30)
print(f"{count}個のファイルを移動しました")

高度な移動操作

進捗表示付き移動

import shutil
import os

def move_with_progress(src, dst):
    def progress_callback(copied, total):
        percent = (copied / total) * 100
        print(f"\r移動進捗: {percent:.1f}%", end='')
    
    # ファイルサイズが大きい場合の進捗表示
    if os.path.isfile(src):
        file_size = os.path.getsize(src)
        if file_size > 1024 * 1024:  # 1MB以上
            print(f"大きなファイルを移動中...")
    
    shutil.move(src, dst)
    print(f"\n移動完了: {dst}")

# 使用例
move_with_progress('large_file.zip', 'backup/large_file.zip')

バックアップ付き移動

import shutil
import os
from datetime import datetime

def move_with_backup(src, dst):
    # 移動先に同名ファイルがある場合はバックアップ
    if os.path.exists(dst):
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        backup_name = f"{dst}.backup_{timestamp}"
        shutil.move(dst, backup_name)
        print(f"既存ファイルをバックアップ: {backup_name}")
    
    shutil.move(src, dst)
    print(f"移動完了: {src} → {dst}")

# 使用例
move_with_backup('new_config.txt', 'config/config.txt')

ファイル移動の検証

移動後の整合性チェック

import shutil
import os
import hashlib

def move_and_verify(src, dst):
    # 移動前のハッシュ値を計算
    with open(src, 'rb') as f:
        original_hash = hashlib.md5(f.read()).hexdigest()
    
    # ファイル移動
    shutil.move(src, dst)
    
    # 移動後のハッシュ値を確認
    with open(dst, 'rb') as f:
        moved_hash = hashlib.md5(f.read()).hexdigest()
    
    if original_hash == moved_hash:
        return f"移動成功: ハッシュ値一致 ({dst})"
    else:
        return f"移動エラー: ハッシュ値不一致"

# 使用例(テキストファイル以外で使用)
# result = move_and_verify('data.bin', 'backup/data.bin')
# print(result)

ディスク容量チェック付き移動

import shutil
import os

def move_with_space_check(src, dst):
    # ファイルサイズを取得
    if os.path.isfile(src):
        file_size = os.path.getsize(src)
    else:
        # ディレクトリの場合は合計サイズを計算
        file_size = sum(
            os.path.getsize(os.path.join(dirpath, filename))
            for dirpath, dirnames, filenames in os.walk(src)
            for filename in filenames
        )
    
    # 移動先の空き容量を確認
    dst_dir = os.path.dirname(dst) or '.'
    free_space = shutil.disk_usage(dst_dir).free
    
    if file_size > free_space:
        return f"エラー: 容量不足 (必要: {file_size}, 空き: {free_space})"
    
    shutil.move(src, dst)
    return f"移動完了: {dst}"

# 使用例
print(move_with_space_check('large_folder', 'external_drive/large_folder'))

まとめ

shutil.move()は以下の特徴を持つ強力な関数です:

  • ファイルとディレクトリの両方に対応
  • 移動先が同じファイルシステム内なら高速な名前変更
  • 異なるファイルシステム間ではコピー後削除を実行
  • 移動先ディレクトリが存在しない場合は自動作成

エラーハンドリング、進捗表示、バックアップ機能を追加することで、より堅牢で使いやすい移動機能を実装できます。

らくらくPython塾 – 読むだけでマスター

■プロンプトだけでオリジナルアプリを開発・公開してみた!!

■AI時代の第一歩!「AI駆動開発コース」はじめました!

テックジム東京本校で先行開始。

■テックジム東京本校

「武田塾」のプログラミング版といえば「テックジム」。
講義動画なし、教科書なし。「進捗管理とコーチング」で効率学習。
より早く、より安く、しかも対面型のプログラミングスクールです。

<短期講習>5日で5万円の「Pythonミニキャンプ」開催中。

<月1開催>放送作家による映像ディレクター養成講座

<オンライン無料>ゼロから始めるPython爆速講座