File Synchronization Tool
Abstract
File Synchronization Tool is a Python utility that keeps files in two directories synchronized. It demonstrates file system operations, hashing, and automation. This project is great for learning about file management, automation, and error handling in Python.
Prerequisites
- Python 3.6 or above
- os, shutil, hashlib (built-in)
Before you Start
Make sure you have Python installed. No external packages are required; all modules used are built-in.
Getting Started
- Create a folder named
file-sync-tool
file-sync-tool
. - Create a file named
file_synchronization_tool.py
file_synchronization_tool.py
. - Copy the code below into your file.
⚙️ File Synchronization Tool
File Synchronization Tool
"""
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
"""
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()
- Run the script:
python file_synchronization_tool.py
python file_synchronization_tool.py
Explanation
Code Breakdown
- Import modules
import os
import shutil
import hashlib
import os
import shutil
import hashlib
- Compare and sync files
def sync_dirs(src, dest):
for filename in os.listdir(src):
src_file = os.path.join(src, filename)
dest_file = os.path.join(dest, filename)
if not os.path.exists(dest_file) or hash_file(src_file) != hash_file(dest_file):
shutil.copy2(src_file, dest_file)
def sync_dirs(src, dest):
for filename in os.listdir(src):
src_file = os.path.join(src, filename)
dest_file = os.path.join(dest, filename)
if not os.path.exists(dest_file) or hash_file(src_file) != hash_file(dest_file):
shutil.copy2(src_file, dest_file)
- Hashing function
def hash_file(path):
with open(path, 'rb') as f:
return hashlib.md5(f.read()).hexdigest()
def hash_file(path):
with open(path, 'rb') as f:
return hashlib.md5(f.read()).hexdigest()
Features
- Syncs files between folders
- Uses hashing for change detection
- Automates backup tasks
- Simple CLI usage
How It Works
- Compares files by hash
- Copies changed/new files
- Ensures destination matches source
Use Cases
- Backup important files
- Mirror folders
- Automate file management
- Keep USB drives synced
Next Steps
You can enhance this project by:
- Adding logging
- Supporting subdirectories
- Scheduling syncs
- Adding a GUI
- Handling file deletions
- Conflict resolution
Enhanced Version Ideas
def sync_with_logging(src, dest):
# Log all sync actions
pass
def sync_subdirs(src, dest):
# Recursively sync folders
pass
def sync_with_logging(src, dest):
# Log all sync actions
pass
def sync_subdirs(src, dest):
# Recursively sync folders
pass
Troubleshooting Tips
- Permission errors: Check file access
- Hash mismatch: Re-run sync
- File not copied: Check source/destination paths
Conclusion
This project teaches file operations, hashing, and automation. Expand it for more robust syncing and scheduling. Useful for backups and file management.
Was this page helpful?
Let us know how we did