ホームページ  >  記事  >  バックエンド開発  >  Python を使用して 2 つのディレクトリ間でファイルを同期する

Python を使用して 2 つのディレクトリ間でファイルを同期する

王林
王林オリジナル
2024-08-16 18:01:091046ブラウズ

Synchronizing Files Between Two Directories Using Python

ディレクトリ間でファイルを同期することは、バックアップを管理したり、複数の保存場所間で一貫性を確保したり、単にデータを整理したりするための一般的なタスクです。

これを行うために利用できるツールは多数ありますが、ディレクトリ同期を処理する Python スクリプトを作成すると、柔軟性と制御が得られます。

このガイドでは、2 つのディレクトリ間でファイルを同期するように設計された Python スクリプトについて説明します。


スクリプトの紹介

スクリプトは、いくつかの重要な Python ライブラリをインポートすることから始まります。

これらには、オペレーティング システムと対話するための os、高レベルのファイル操作のための shutil、ファイルを比較するための filecmp、コマンドライン引数を解析するための argparse、および時間のかかる操作中に進行状況バーを表示するための tqdm が含まれます。

これらのライブラリは連携して、ディレクトリ同期のための堅牢なソリューションを作成します。

import os
import shutil
import filecmp
import argparse
from tqdm import tqdm

スクリプトは主に Python 組み込みモジュールを使用しますが、進行状況バーには tqdmlibrary が使用されます。これは次の方法でインストールする必要があります。

pip install tqdm

ディレクトリの確認と準備

同期を開始する前に、スクリプトはソース ディレクトリが存在するかどうかを確認する必要があります。

宛先ディレクトリが存在しない場合は、スクリプトによって作成されます。

この手順は、ディレクトリの欠落による問題が発生せずに同期プロセスがスムーズに実行されることを確認するために重要です。

# Function to check if the source and destination directories exist
def check_directories(src_dir, dst_dir):
    # Check if the source directory exists
    if not os.path.exists(src_dir):
        print(f"\nSource directory '{src_dir}' does not exist.")
        return False
    # Create the destination directory if it does not exist
    if not os.path.exists(dst_dir):
        os.makedirs(dst_dir)
        print(f"\nDestination directory '{dst_dir}' created.")
    return True

check_directories 関数は、ソース ディレクトリと宛先ディレクトリの両方が同期の準備ができていることを確認します。仕組みは次のとおりです:

  • この関数は os.path.exists() を使用してディレクトリが存在するかどうかを確認します。
  • ソース ディレクトリが見つからない場合、スクリプトはユーザーに通知し、実行を停止します。
  • 宛先ディレクトリが見つからない場合、スクリプトは os.makedirs() を使用して自動的に作成します。これにより、必要なディレクトリ構造が確実に配置されます。

ディレクトリ間でファイルを同期する

スクリプトの主な仕事は、ソース ディレクトリと宛先ディレクトリの間でファイルを同期することです。

sync_directories 関数は、最初にソース ディレクトリを調べてすべてのファイルとサブディレクトリのリストを収集することで、このタスクを処理します。

os.walk 関数は、ディレクトリ ツリー内にファイル名を生成することで役立ち、スクリプトがソース ディレクトリ内のすべてのファイルとフォルダーをキャプチャできるようになります。

# Function to synchronize files between two directories
def sync_directories(src_dir, dst_dir, delete=False):
    # Get a list of all files and directories in the source directory
    files_to_sync = []
    for root, dirs, files in os.walk(src_dir):
        for directory in dirs:
            files_to_sync.append(os.path.join(root, directory))
        for file in files:
            files_to_sync.append(os.path.join(root, file))

    # Iterate over each file in the source directory with a progress bar
    with tqdm(total=len(files_to_sync), desc="Syncing files", unit="file") as pbar:
        # Iterate over each file in the source directory
        for source_path in files_to_sync:
            # Get the corresponding path in the replica directory
            replica_path = os.path.join(dst_dir, os.path.relpath(source_path, src_dir))

            # Check if path is a directory and create it in the replica directory if it does not exist
            if os.path.isdir(source_path):
                if not os.path.exists(replica_path):
                    os.makedirs(replica_path)
            # Copy all files from the source directory to the replica directory
            else:
                # Check if the file exists in the replica directory and if it is different from the source file
                if not os.path.exists(replica_path) or not filecmp.cmp(source_path, replica_path, shallow=False):
                    # Set the description of the progress bar and print the file being copied
                    pbar.set_description(f"Processing '{source_path}'")
                    print(f"\nCopying {source_path} to {replica_path}")

                    # Copy the file from the source directory to the replica directory
                    shutil.copy2(source_path, replica_path)

            # Update the progress bar
            pbar.update(1)

ファイルとディレクトリのリストがコンパイルされると、スクリプトは tqdm によって提供される進行状況バーを使用して、同期プロセスに関するフィードバックをユーザーに提供します。

ソース内のファイルとディレクトリごとに、スクリプトは宛先内の対応するパスを計算します。

パスがディレクトリの場合、スクリプトはそのパスが宛先に存在することを確認します。

パスがファイルの場合、スクリプトはそのファイルが宛先にすでに存在するかどうか、またソース ファイルと同一であるかどうかをチェックします。

ファイルが見つからないか異なる場合、スクリプトはそのファイルを宛先にコピーします。

このようにして、スクリプトは宛先ディレクトリをソース ディレクトリと同じ最新の状態に保ちます。


余分なファイルのクリーンアップ

このスクリプトには、ソース ディレクトリにない宛先ディレクトリ内のファイルを削除するオプション機能もあります。

これは、ユーザーが設定できる --delete フラグによって制御されます。

このフラグが使用される場合、スクリプトは宛先ディレクトリを通過し、各ファイルとフォルダーをソースと比較します。

ソースにないものを宛先に見つけた場合、スクリプトはそれを削除します。

これにより、宛先ディレクトリがソース ディレクトリの正確なコピーであることが保証されます。

# Clean up files in the destination directory that are not in the source directory, if delete flag is set
    if delete:
        # Get a list of all files in the destination directory
        files_to_delete = []
        for root, dirs, files in os.walk(dst_dir):
            for directory in dirs:
                files_to_delete.append(os.path.join(root, directory))
            for file in files:
                files_to_delete.append(os.path.join(root, file))

        # Iterate over each file in the destination directory with a progress bar
        with tqdm(total=len(files_to_delete), desc="Deleting files", unit="file") as pbar:
            # Iterate over each file in the destination directory
            for replica_path in files_to_delete:
                # Check if the file exists in the source directory
                source_path = os.path.join(src_dir, os.path.relpath(replica_path, dst_dir))
                if not os.path.exists(source_path):
                    # Set the description of the progress bar
                    pbar.set_description(f"Processing '{replica_path}'")
                    print(f"\nDeleting {replica_path}")

                    # Check if the path is a directory and remove it
                    if os.path.isdir(replica_path):
                        shutil.rmtree(replica_path)
                    else:
                        # Remove the file from the destination directory
                        os.remove(replica_path)

                # Update the progress bar
                pbar.update(1)

スクリプトのこの部分では、同期プロセスと同様の手法を使用します。

os.walk() を使用してファイルとディレクトリを収集し、tqdm を使用して進行状況を表示します。
shutil.rmtree() 関数はディレクトリの削除に使用され、os.remove() は個々のファイルを処理します。


スクリプトの実行

このスクリプトは、ソース ディレクトリと宛先ディレクトリを指定する引数を使用して、コマンド ラインから実行されるように設計されています。

argparse モジュールを使用すると、これらの引数の処理が簡単になり、ユーザーはスクリプトの実行時に必要なパスとオプションを指定するだけで済みます。

# Main function to parse command line arguments and synchronize directories
if __name__ == "__main__":
    # Parse command line arguments
    parser = argparse.ArgumentParser(description="Synchronize files between two directories.")
    parser.add_argument("source_directory", help="The source directory to synchronize from.")
    parser.add_argument("destination_directory", help="The destination directory to synchronize to.")
    parser.add_argument("-d", "--delete", action="store_true",
                        help="Delete files in destination that are not in source.")
    args = parser.parse_args()

    # If the delete flag is set, print a warning message
    if args.delete:
        print("\nExtraneous files in the destination will be deleted.")

    # Check the source and destination directories
    if not check_directories(args.source_directory, args.destination_directory):
        exit(1)

    # Synchronize the directories
    sync_directories(args.source_directory, args.destination_directory, args.delete)
    print("\nSynchronization complete.")

main 関数はすべてをまとめます。

コマンドライン引数を処理し、ディレクトリをチェックして、同期を実行します。

--delete フラグが設定されている場合、余分なファイルのクリーンアップも処理されます。


さまざまなオプションを使用してスクリプトを実行する方法の例をいくつか見てみましょう。

送信元から宛先へ

python file_sync.py d:\sync d:\sync_copy 
Destination directory 'd:\sync2' created.
Processing 'd:\sync\video.mp4':   0%|                                                                                                   | 0/5 [00:00<?, ?file/s]
Copying d:\sync\video.mp4 to d:\sync2\video.mp4
Processing 'd:\sync\video_final.mp4':  20%|██████████████████▌                                                                          | 1/5 [00:00<?, ?file/s] 
Copying d:\sync\video_final.mp4 to d:\sync2\video_final.mp4
Processing 'd:\sync\video_single - Copy (2).mp4':  40%|████████████████████████████████▍                                                | 2/5 [00:00<?, ?file/s] 
Copying d:\sync\video_single - Copy (2).mp4 to d:\sync2\video_single - Copy (2).mp4
Processing 'd:\sync\video_single - Copy.mp4':  60%|█████████████████████████████████████████████▌                              | 3/5 [00:00<00:00, 205.83file/s]
Copying d:\sync\video_single - Copy.mp4 to d:\sync2\video_single - Copy.mp4
Processing 'd:\sync\video_single.mp4':  80%|██████████████████████████████████████████████████████████████████▍                | 4/5 [00:00<00:00, 274.44file/s] 
Copying d:\sync\video_single.mp4 to d:\sync2\video_single.mp4
Processing 'd:\sync\video_single.mp4': 100%|███████████████████████████████████████████████████████████████████████████████████| 5/5 [00:00<00:00, 343.05file/s] 

Synchronization complete.

Source to Destination with Cleanup of Extra Files

python file_sync.py d:\sync d:\sync_copy -d
Extraneous files in the destination will be deleted.
Syncing files: 100%|████████████████████████████████████████████████████████████████████████████████████████████████████████████| 5/5 [00:00<00:00, 63.29file/s]
Deleting files: 100%|███████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 5/5 [00:00<?, ?file/s] 

Synchronization complete.

Conclusion

This Python script offers a powerful and flexible way to synchronize files between two directories.

It uses key libraries like os, shutil, and filecmp, and enhances the user experience with tqdm for tracking progress.

This ensures that your data is consistently and efficiently synchronized.
Whether you're maintaining backups or ensuring consistency across storage locations, this script can be a valuable tool in your toolkit.

以上がPython を使用して 2 つのディレクトリ間でファイルを同期するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。