」工欲善其事,必先利其器。「—孔子《論語.錄靈公》
首頁 > 程式設計 > 使用 Python 同步兩個目錄之間的文件

使用 Python 同步兩個目錄之間的文件

發佈於2024-08-16
瀏覽:242

Synchronizing Files Between Two Directories Using Python

Synchronizing files between directories is a common task for managing backups, ensuring consistency across multiple storage locations, or simply keeping data organized.

While there are many tools available to do this, creating a Python script to handle directory synchronization offers flexibility and control.

This guide will walk you through a Python script designed to synchronize files between two directories.


Introduction to the Script

The script begins by importing several essential Python libraries.

These include os for interacting with the operating system, shutilfor high-level file operations, filecmpfor comparing files, argparsefor parsing command-line arguments, and tqdmfor displaying progress bars during lengthy operations.

These libraries work together to create a robust solution for directory synchronization.

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

The scripts uses mainly Python built-in modules, but for the progress bar is uses the tqdmlibrary, which needs to the installed with:

pip install tqdm

Checking and Preparing Directories

Before starting the synchronization, the script needs to check if the source directory exists.

If the destination directory doesn't exist, the script will create it.

This step is important to make sure the synchronization process can run smoothly without any issues caused by missing directories.

# 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

The check_directories function makes sure that both the source and destination directories are ready for synchronization. Here's how it works:

  • The function uses os.path.exists() to check if the directories exist.
  • If the source directory is missing, the script tells the user and stops running.
  • If the destination directory is missing, the script creates it automatically using os.makedirs(). This ensures that the necessary directory structure is in place.

Synchronizing Files Between Directories

The main job of the script is to synchronize files between the source and destination directories.

The sync_directories function handles this task by first going through the source directory to gather a list of all files and subdirectories.

The os.walk function helps by generating file names in the directory tree, allowing the script to capture every file and folder within the source directory.

# 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)

Once the list of files and directories is compiled, the script uses a progress bar provided by tqdm to give the user feedback on the synchronization process.

For each file and directory in the source, the script calculates the corresponding path in the destination.

If the path is a directory, the script ensures it exists in the destination.

If the path is a file, the script checks whether the file already exists in the destination and whether it is identical to the source file.

If the file is missing or different, the script copies it to the destination.

This way, the script keeps the destination directory up-to-date with the source directory.


Cleaning Up Extra Files

The script also has an optional feature to delete files in the destination directory that are not in the source directory.

This is controlled by a --delete flag that the user can set.

If this flag is used, the script goes through the destination directory and compares each file and folder to the source.

If it finds anything in the destination that isn't in the source, the script deletes it.

This ensures that the destination directory is an exact copy of the source directory.

# 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)

This part of the script uses similar techniques as the synchronization process.

It uses os.walk() to gather files and directories and tqdm to show progress.
The shutil.rmtree() function is used to remove directories, while os.remove() handles individual files.


Running the Script

The script is designed to be run from the command line, with arguments specifying the source and destination directories.

The argparse module makes it easy to handle these arguments, allowing users to simply provide the necessary paths and options when running the script.

# 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.")

The main function brings everything together.

It processes the command-line arguments, checks the directories, and then performs the synchronization.

If the --delete flag is set, it also handles the cleanup of extra files.


Examples

Let's see some examples of how to run the script with the different options.

Source to Destination

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



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





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.

版本聲明 本文轉載於:https://dev.to/devasservice/synchronizing-files-between-two-directories-using-python-19li?1如有侵犯,請聯絡[email protected]刪除
最新教學 更多>
  • 從零到 Web 開發人員:掌握 PHP 基礎知識
    從零到 Web 開發人員:掌握 PHP 基礎知識
    掌握PHP基礎至關重要:安裝PHP建立PHP檔案運行程式碼理解變數和資料類型使用表達式和運算子建立實際專案以提高技能 PHP開發入門:掌握PHP基礎PHP是一種用途廣泛、功能強大的腳本語言,用於創建動態且互動式Web應用程式。對於初學者來說,掌握PHP的基本知識至關重要。 一、安裝PHP在本地開發機...
    程式設計 發佈於2024-11-05
  • 緩衝區:Node.js
    緩衝區:Node.js
    Node.js 中緩衝區的簡單指南 Node.js 中的 Buffer 用於處理原始二進位數據,這在處理流、文件或網路數據時非常有用。 如何建立緩衝區 來自字串: const buf = Buffer.from('Hello'); 分配特定大小的Buffer...
    程式設計 發佈於2024-11-05
  • 掌握 Node.js 中的版本管理
    掌握 Node.js 中的版本管理
    作為開發者,我們經常遇到需要不同 Node.js 版本的專案。對於可能不經常參與 Node.js 專案的新手和經驗豐富的開發人員來說,這種情況都是一個陷阱:確保每個專案使用正確的 Node.js 版本。 在安裝依賴項並執行專案之前,驗證您的 Node.js 版本是否符合或至少相容專案的要求至關重要...
    程式設計 發佈於2024-11-05
  • 如何在 Go 二進位檔案中嵌入 Git 修訂資訊以進行故障排除?
    如何在 Go 二進位檔案中嵌入 Git 修訂資訊以進行故障排除?
    確定Go 二進位檔案中的Git 修訂版部署程式碼時,將二進位檔案與建置它們的git 修訂版關聯起來會很有幫助排除故障的目的。然而,直接使用修訂號更新原始程式碼是不可行的,因為它會改變原始程式碼。 解決方案:利用建造標誌解決此挑戰的方法包括利用建造標誌。透過使用建置標誌在主套件中設定當前 git 修訂...
    程式設計 發佈於2024-11-05
  • 常見 HTML 標籤:視角
    常見 HTML 標籤:視角
    HTML(超文本標記語言)構成了 Web 開發的基礎,是互聯網上每個網頁的結構。透過了解最常見的 HTML 標籤及其高級用途,到 2024 年,開發人員可以創建更有效率、更易於存取且更具視覺吸引力的網頁。在這篇文章中,我們將探討這些 HTML 標籤及其最高級的用例,以協助您提升 Web 開發技能。 ...
    程式設計 發佈於2024-11-05
  • CSS 媒體查詢
    CSS 媒體查詢
    確保網站在各種裝置上無縫運作比以往任何時候都更加重要。隨著用戶透過桌上型電腦、筆記型電腦、平板電腦和智慧型手機造訪網站,響應式設計已成為必要。響應式設計的核心在於媒體查詢,這是一項強大的 CSS 功能,可讓開發人員根據使用者裝置的特徵應用不同的樣式。在本文中,我們將探討什麼是媒體查詢、它們如何運作以...
    程式設計 發佈於2024-11-05
  • 了解 JavaScript 中的提升:綜合指南
    了解 JavaScript 中的提升:綜合指南
    JavaScript 中的提升 提升是一種行為,其中變數和函數聲明在先前被移動(或「提升」)到其包含範圍(全域範圍或函數範圍)的頂部程式碼被執行。這意味著您可以在程式碼中實際聲明變數和函數之前使用它們。 變數提升 變數 用 var 宣告的變數被提升...
    程式設計 發佈於2024-11-05
  • 將 Stripe 整合到單一產品 Django Python 商店中
    將 Stripe 整合到單一產品 Django Python 商店中
    In the first part of this series, we created a Django online shop with htmx. In this second part, we'll handle orders using Stripe. What We'll...
    程式設計 發佈於2024-11-05
  • 在 Laravel 測試排隊作業的技巧
    在 Laravel 測試排隊作業的技巧
    使用 Laravel 應用程式時,經常會遇到命令需要執行昂貴任務的情況。為了避免阻塞主進程,您可能決定將任務卸載到可以由佇列處理的作業。 讓我們來看一個例子。想像一下指令 app:import-users 需要讀取一個大的 CSV 檔案並為每個條目建立一個使用者。該命令可能如下所示: /* Imp...
    程式設計 發佈於2024-11-05
  • 如何創建人類層級的自然語言理解 (NLU) 系統
    如何創建人類層級的自然語言理解 (NLU) 系統
    Scope: Creating an NLU system that fully understands and processes human languages in a wide range of contexts, from conversations to literature. ...
    程式設計 發佈於2024-11-05
  • 如何使用 JSTL 迭代 HashMap 中的 ArrayList?
    如何使用 JSTL 迭代 HashMap 中的 ArrayList?
    使用JSTL 迭代HashMap 中的ArrayList在Web 開發中,JSTL(JavaServer Pages 標準標記庫)提供了一組標記來簡化JSP 中的常見任務( Java 伺服器頁面)。其中一項任務是迭代資料結構。 要迭代 HashMap 及其中包含的 ArrayList,可以使用 JS...
    程式設計 發佈於2024-11-05
  • Encore.ts — 比 ElysiaJS 和 Hono 更快
    Encore.ts — 比 ElysiaJS 和 Hono 更快
    几个月前,我们发布了 Encore.ts — TypeScript 的开源后端框架。 由于已经有很多框架,我们想分享我们做出的一些不常见的设计决策以及它们如何带来卓越的性能数据。 性能基准 我们之前发布的基准测试显示 Encore.ts 比 Express 快 9 倍,比 Fasti...
    程式設計 發佈於2024-11-05
  • 為什麼使用 + 對字串文字進行字串連接失敗?
    為什麼使用 + 對字串文字進行字串連接失敗?
    連接字串文字與字串在 C 中,運算子可用於連接字串和字串文字。但是,此功能存在限制,可能會導致混亂。 在問題中,作者嘗試連接字串文字「Hello」、「,world」和「!」以兩種不同的方式。第一個例子:const string hello = "Hello"; const str...
    程式設計 發佈於2024-11-05
  • React 重新渲染:最佳效能的最佳實踐
    React 重新渲染:最佳效能的最佳實踐
    React高效率的渲染機制是其受歡迎的關鍵原因之一。然而,隨著應用程式複雜性的增加,管理元件重新渲染對於最佳化效能變得至關重要。讓我們探索優化 React 渲染行為並避免不必要的重新渲染的最佳實踐。 1. 使用 React.memo() 作為函數式元件 React.memo() 是...
    程式設計 發佈於2024-11-05
  • 如何實作條件列建立:探索 Pandas DataFrame 中的 If-Elif-Else?
    如何實作條件列建立:探索 Pandas DataFrame 中的 If-Elif-Else?
    Creating a Conditional Column: If-Elif-Else in Pandas給定的問題要求將新列新增至DataFrame 中基於一系列條件標準。挑戰在於在實現這些條件的同時保持程式碼效率和可讀性。 使用函數應用程式的解決方案一種方法涉及創建一個將每一行映射到所需結果的函...
    程式設計 發佈於2024-11-05

免責聲明: 提供的所有資源部分來自互聯網,如果有侵犯您的版權或其他權益,請說明詳細緣由並提供版權或權益證明然後發到郵箱:[email protected] 我們會在第一時間內為您處理。

Copyright© 2022 湘ICP备2022001581号-3