Skip to content

File Synchronization Tool

Abstract

Create a File Synchronization Tool that synchronizes files between two directories. The app detects new or updated files, copies them, and provides a summary of actions. This project demonstrates file handling, directory traversal, and GUI development in Python.

Prerequisites

  • Python 3.6 or above
  • Text Editor or IDE
  • Basic understanding of Python syntax
  • Familiarity with Tkinter for GUI development
  • Knowledge of file and directory operations

Getting Started

Creating a new project

  1. Create a new project folder and name it file_synchronization_toolfile_synchronization_tool.
  2. Create a new file inside the folder and name it file_synchronization_tool.pyfile_synchronization_tool.py.
  3. Open the project folder in your favorite text editor or IDE.
  4. Copy the code below and paste it into the file_synchronization_tool.pyfile_synchronization_tool.py file.

Write the code

โš™๏ธ file_synchronization_tool.py
file_synchronization_tool.py
"""
File Synchronization Tool
 
A tool to synchronize files between two directories with the following features:
- Detect and copy new or updated files
- Delete files that no longer exist in the source directory
- Provide a summary of synchronization actions
"""
 
import os
import shutil
from tkinter import Tk, Label, Entry, Button, messagebox, filedialog
 
 
class FileSynchronizationTool:
    def __init__(self, root):
        self.root = root
        self.root.title("File Synchronization Tool")
 
        self.source_dir = ""
        self.target_dir = ""
 
        self.setup_ui()
 
    def setup_ui(self):
        """Set up the user interface."""
        Label(self.root, text="Source Directory:").grid(row=0, column=0, padx=10, pady=10)
        self.source_entry = Entry(self.root, width=50)
        self.source_entry.grid(row=0, column=1, padx=10, pady=10)
        Button(self.root, text="Browse", command=self.browse_source).grid(row=0, column=2, padx=10, pady=10)
 
        Label(self.root, text="Target Directory:").grid(row=1, column=0, padx=10, pady=10)
        self.target_entry = Entry(self.root, width=50)
        self.target_entry.grid(row=1, column=1, padx=10, pady=10)
        Button(self.root, text="Browse", command=self.browse_target).grid(row=1, column=2, padx=10, pady=10)
 
        Button(self.root, text="Synchronize", command=self.synchronize).grid(row=2, column=0, columnspan=3, pady=20)
 
    def browse_source(self):
        """Browse for the source directory."""
        self.source_dir = filedialog.askdirectory()
        self.source_entry.delete(0, "end")
        self.source_entry.insert(0, self.source_dir)
 
    def browse_target(self):
        """Browse for the target directory."""
        self.target_dir = filedialog.askdirectory()
        self.target_entry.delete(0, "end")
        self.target_entry.insert(0, self.target_dir)
 
    def synchronize(self):
        """Synchronize files between the source and target directories."""
        if not self.source_dir or not self.target_dir:
            messagebox.showerror("Error", "Both source and target directories must be selected.")
            return
 
        if not os.path.exists(self.source_dir):
            messagebox.showerror("Error", "Source directory does not exist.")
            return
 
        if not os.path.exists(self.target_dir):
            os.makedirs(self.target_dir)
 
        actions = []
 
        # Copy new and updated files
        for root, dirs, files in os.walk(self.source_dir):
            relative_path = os.path.relpath(root, self.source_dir)
            target_root = os.path.join(self.target_dir, relative_path)
 
            if not os.path.exists(target_root):
                os.makedirs(target_root)
 
            for file in files:
                source_file = os.path.join(root, file)
                target_file = os.path.join(target_root, file)
 
                if not os.path.exists(target_file) or os.path.getmtime(source_file) > os.path.getmtime(target_file):
                    shutil.copy2(source_file, target_file)
                    actions.append(f"Copied: {source_file} -> {target_file}")
 
        # Delete files that no longer exist in the source directory
        for root, dirs, files in os.walk(self.target_dir):
            relative_path = os.path.relpath(root, self.target_dir)
            source_root = os.path.join(self.source_dir, relative_path)
 
            for file in files:
                target_file = os.path.join(root, file)
                source_file = os.path.join(source_root, file)
 
                if not os.path.exists(source_file):
                    os.remove(target_file)
                    actions.append(f"Deleted: {target_file}")
 
        # Show summary
        if actions:
            messagebox.showinfo("Synchronization Complete", "\n".join(actions))
        else:
            messagebox.showinfo("Synchronization Complete", "No changes were made.")
 
 
def main():
    root = Tk()
    app = FileSynchronizationTool(root)
    root.mainloop()
 
 
if __name__ == "__main__":
    main()
 
file_synchronization_tool.py
"""
File Synchronization Tool
 
A tool to synchronize files between two directories with the following features:
- Detect and copy new or updated files
- Delete files that no longer exist in the source directory
- Provide a summary of synchronization actions
"""
 
import os
import shutil
from tkinter import Tk, Label, Entry, Button, messagebox, filedialog
 
 
class FileSynchronizationTool:
    def __init__(self, root):
        self.root = root
        self.root.title("File Synchronization Tool")
 
        self.source_dir = ""
        self.target_dir = ""
 
        self.setup_ui()
 
    def setup_ui(self):
        """Set up the user interface."""
        Label(self.root, text="Source Directory:").grid(row=0, column=0, padx=10, pady=10)
        self.source_entry = Entry(self.root, width=50)
        self.source_entry.grid(row=0, column=1, padx=10, pady=10)
        Button(self.root, text="Browse", command=self.browse_source).grid(row=0, column=2, padx=10, pady=10)
 
        Label(self.root, text="Target Directory:").grid(row=1, column=0, padx=10, pady=10)
        self.target_entry = Entry(self.root, width=50)
        self.target_entry.grid(row=1, column=1, padx=10, pady=10)
        Button(self.root, text="Browse", command=self.browse_target).grid(row=1, column=2, padx=10, pady=10)
 
        Button(self.root, text="Synchronize", command=self.synchronize).grid(row=2, column=0, columnspan=3, pady=20)
 
    def browse_source(self):
        """Browse for the source directory."""
        self.source_dir = filedialog.askdirectory()
        self.source_entry.delete(0, "end")
        self.source_entry.insert(0, self.source_dir)
 
    def browse_target(self):
        """Browse for the target directory."""
        self.target_dir = filedialog.askdirectory()
        self.target_entry.delete(0, "end")
        self.target_entry.insert(0, self.target_dir)
 
    def synchronize(self):
        """Synchronize files between the source and target directories."""
        if not self.source_dir or not self.target_dir:
            messagebox.showerror("Error", "Both source and target directories must be selected.")
            return
 
        if not os.path.exists(self.source_dir):
            messagebox.showerror("Error", "Source directory does not exist.")
            return
 
        if not os.path.exists(self.target_dir):
            os.makedirs(self.target_dir)
 
        actions = []
 
        # Copy new and updated files
        for root, dirs, files in os.walk(self.source_dir):
            relative_path = os.path.relpath(root, self.source_dir)
            target_root = os.path.join(self.target_dir, relative_path)
 
            if not os.path.exists(target_root):
                os.makedirs(target_root)
 
            for file in files:
                source_file = os.path.join(root, file)
                target_file = os.path.join(target_root, file)
 
                if not os.path.exists(target_file) or os.path.getmtime(source_file) > os.path.getmtime(target_file):
                    shutil.copy2(source_file, target_file)
                    actions.append(f"Copied: {source_file} -> {target_file}")
 
        # Delete files that no longer exist in the source directory
        for root, dirs, files in os.walk(self.target_dir):
            relative_path = os.path.relpath(root, self.target_dir)
            source_root = os.path.join(self.source_dir, relative_path)
 
            for file in files:
                target_file = os.path.join(root, file)
                source_file = os.path.join(source_root, file)
 
                if not os.path.exists(source_file):
                    os.remove(target_file)
                    actions.append(f"Deleted: {target_file}")
 
        # Show summary
        if actions:
            messagebox.showinfo("Synchronization Complete", "\n".join(actions))
        else:
            messagebox.showinfo("Synchronization Complete", "No changes were made.")
 
 
def main():
    root = Tk()
    app = FileSynchronizationTool(root)
    root.mainloop()
 
 
if __name__ == "__main__":
    main()
 

Key Features

  • Detect and copy new or updated files
  • Delete files that no longer exist in the source directory
  • Provide a summary of synchronization actions
  • GUI interface for easy selection of directories

Explanation

Directory Selection

The app uses Tkinterโ€™s file dialog to let users select source and target directories:

file_synchronization_tool.py
self.source_dir = filedialog.askdirectory()
self.target_dir = filedialog.askdirectory()
file_synchronization_tool.py
self.source_dir = filedialog.askdirectory()
self.target_dir = filedialog.askdirectory()

Synchronization Logic

The tool compares files in both directories and copies new or updated files:

file_synchronization_tool.py
if not os.path.exists(destination_file) or os.path.getmtime(source_file) > os.path.getmtime(destination_file):
    shutil.copy2(source_file, destination_file)
file_synchronization_tool.py
if not os.path.exists(destination_file) or os.path.getmtime(source_file) > os.path.getmtime(destination_file):
    shutil.copy2(source_file, destination_file)

User Interface

The GUI provides buttons for browsing directories and starting synchronization:

file_synchronization_tool.py
Button(self.root, text="Synchronize", command=self.synchronize).grid(row=2, column=0, columnspan=3, pady=20)
file_synchronization_tool.py
Button(self.root, text="Synchronize", command=self.synchronize).grid(row=2, column=0, columnspan=3, pady=20)

Running the Application

  1. Save the file.
  2. Run the application:
python file_synchronization_tool.py
python file_synchronization_tool.py

Conclusion

This File Synchronization Tool is a practical project for learning about file operations, directory traversal, and GUI development in Python. You can extend it by adding logging, conflict resolution, or scheduling features.

Was this page helpful?

Let us know how we did