Automatically Organize Your Downloads Folder with Python
Your Downloads folder is a mess. PDFs mixed with images, spreadsheets buried under zip files, and that important document you downloaded last week? Good luck finding it. You've probably cleaned it up manually a dozen times, only to watch it descend back into chaos within days.
What if a Python script could do this for you—automatically, every time you run it?
Today, we're building a file organizer that sorts your downloads by file type. No more manual cleanup. No more searching through hundreds of files. Just organized folders, automatically.
What You'll Learn
- How to work with files and directories in Python
- Using the
pathlibmodule for modern file operations - Organizing code with functions for reusability
- Error handling for real-world reliability
Prerequisites
- Python 3.8 or higher
- No additional libraries required (we're using built-in modules!)
- Access to your Downloads folder
The Problem
Every day, files accumulate in your Downloads folder:
- Browser downloads
- Email attachments you save
- Files from messaging apps
- Screenshots and images
- Documents from various sources
Within a week, you have hundreds of files with no organization. Finding anything requires scrolling through a chaotic list, and the visual clutter is mentally draining.
The Solution
We'll create a Python script that:
- Scans your Downloads folder
- Identifies each file's type by extension
- Creates organized subfolders (Documents, Images, Videos, etc.)
- Moves each file to its appropriate folder
- Handles duplicates gracefully
Step 1: Setting Up File Type Categories
First, we need to define what types of files we're dealing with and where they should go:
1# Define file categories and their extensions2FILE_CATEGORIES = {3 "Documents": [".pdf", ".doc", ".docx", ".txt", ".rtf", ".odt", ".xls", ".xlsx", ".ppt", ".pptx", ".csv"],4 "Images": [".jpg", ".jpeg", ".png", ".gif", ".bmp", ".svg", ".webp", ".ico", ".tiff"],5 "Videos": [".mp4", ".avi", ".mkv", ".mov", ".wmv", ".flv", ".webm"],6 "Audio": [".mp3", ".wav", ".flac", ".aac", ".ogg", ".wma", ".m4a"],7 "Archives": [".zip", ".rar", ".7z", ".tar", ".gz", ".bz2"],8 "Code": [".py", ".js", ".html", ".css", ".java", ".cpp", ".c", ".json", ".xml"],9 "Executables": [".exe", ".msi", ".dmg", ".app", ".deb", ".rpm"],10}
This dictionary maps folder names to lists of file extensions. When we encounter a .pdf file, we know it belongs in "Documents".
Step 2: Creating the Category Lookup Function
We need a function that takes a file extension and returns the appropriate category:
1def get_category(file_extension):2 """3 Determine which category a file belongs to based on its extension.45 Args:6 file_extension: The file extension (e.g., '.pdf')78 Returns:9 The category name (e.g., 'Documents') or 'Other' if not recognized10 """11 # Convert to lowercase for consistent matching12 ext = file_extension.lower()1314 # Search through categories for a match15 for category, extensions in FILE_CATEGORIES.items():16 if ext in extensions:17 return category1819 # If no match found, put in 'Other' folder20 return "Other"
This function handles unknown file types by putting them in an "Other" folder, so nothing gets lost.
Step 3: Handling Duplicate Files
What happens if you download report.pdf twice? We need to handle this gracefully:
1def get_unique_filename(destination_folder, filename):2 """3 Generate a unique filename if the file already exists.45 Args:6 destination_folder: Path object for the destination7 filename: Original filename89 Returns:10 A unique filename (original or with a number suffix)11 """12 from pathlib import Path1314 destination = destination_folder / filename1516 # If file doesn't exist, use original name17 if not destination.exists():18 return filename1920 # Split filename into name and extension21 stem = Path(filename).stem # 'report' from 'report.pdf'22 suffix = Path(filename).suffix # '.pdf'2324 # Try adding numbers until we find a unique name25 counter = 126 while True:27 new_filename = f"{stem}_{counter}{suffix}"28 if not (destination_folder / new_filename).exists():29 return new_filename30 counter += 1
This creates filenames like report_1.pdf, report_2.pdf when duplicates are found.
Step 4: The Main Organization Function
Now we bring it all together:
1def organize_folder(source_folder):2 """3 Organize all files in the source folder into categorized subfolders.45 Args:6 source_folder: Path to the folder to organize (e.g., Downloads)78 Returns:9 Dictionary with counts of files moved per category10 """11 from pathlib import Path12 import shutil1314 source = Path(source_folder)1516 # Verify the folder exists17 if not source.exists():18 print(f"Error: Folder '{source_folder}' does not exist!")19 return {}2021 # Track how many files we move22 moved_counts = {}2324 # Process each file in the folder25 for item in source.iterdir():26 # Skip directories - we only want files27 if item.is_dir():28 continue2930 # Skip hidden files (starting with .)31 if item.name.startswith('.'):32 continue3334 # Determine the category for this file35 category = get_category(item.suffix)3637 # Create the category folder if it doesn't exist38 category_folder = source / category39 category_folder.mkdir(exist_ok=True)4041 # Get a unique filename to avoid overwriting42 unique_name = get_unique_filename(category_folder, item.name)43 destination = category_folder / unique_name4445 # Move the file46 try:47 shutil.move(str(item), str(destination))4849 # Update our count50 moved_counts[category] = moved_counts.get(category, 0) + 151 print(f"Moved: {item.name} -> {category}/{unique_name}")5253 except Exception as e:54 print(f"Error moving {item.name}: {e}")5556 return moved_counts
The Complete Script
1#!/usr/bin/env python32"""3File Organizer - Automatically sort files into categorized folders.4Author: Alex Rodriguez56This script organizes files in a folder (like Downloads) by moving them7into subfolders based on their file type (Documents, Images, Videos, etc.).8"""910import shutil11from pathlib import Path121314# Define file categories and their extensions15FILE_CATEGORIES = {16 "Documents": [".pdf", ".doc", ".docx", ".txt", ".rtf", ".odt", ".xls", ".xlsx", ".ppt", ".pptx", ".csv"],17 "Images": [".jpg", ".jpeg", ".png", ".gif", ".bmp", ".svg", ".webp", ".ico", ".tiff"],18 "Videos": [".mp4", ".avi", ".mkv", ".mov", ".wmv", ".flv", ".webm"],19 "Audio": [".mp3", ".wav", ".flac", ".aac", ".ogg", ".wma", ".m4a"],20 "Archives": [".zip", ".rar", ".7z", ".tar", ".gz", ".bz2"],21 "Code": [".py", ".js", ".html", ".css", ".java", ".cpp", ".c", ".json", ".xml"],22 "Executables": [".exe", ".msi", ".dmg", ".app", ".deb", ".rpm"],23}242526def get_category(file_extension):27 """28 Determine which category a file belongs to based on its extension.2930 Args:31 file_extension: The file extension (e.g., '.pdf')3233 Returns:34 The category name (e.g., 'Documents') or 'Other' if not recognized35 """36 ext = file_extension.lower()3738 for category, extensions in FILE_CATEGORIES.items():39 if ext in extensions:40 return category4142 return "Other"434445def get_unique_filename(destination_folder, filename):46 """47 Generate a unique filename if the file already exists.4849 Args:50 destination_folder: Path object for the destination51 filename: Original filename5253 Returns:54 A unique filename (original or with a number suffix)55 """56 destination = destination_folder / filename5758 if not destination.exists():59 return filename6061 stem = Path(filename).stem62 suffix = Path(filename).suffix6364 counter = 165 while True:66 new_filename = f"{stem}_{counter}{suffix}"67 if not (destination_folder / new_filename).exists():68 return new_filename69 counter += 1707172def organize_folder(source_folder):73 """74 Organize all files in the source folder into categorized subfolders.7576 Args:77 source_folder: Path to the folder to organize (e.g., Downloads)7879 Returns:80 Dictionary with counts of files moved per category81 """82 source = Path(source_folder)8384 if not source.exists():85 print(f"Error: Folder '{source_folder}' does not exist!")86 return {}8788 print(f"\nOrganizing files in: {source}")89 print("-" * 50)9091 moved_counts = {}9293 for item in source.iterdir():94 if item.is_dir():95 continue9697 if item.name.startswith('.'):98 continue99100 category = get_category(item.suffix)101102 category_folder = source / category103 category_folder.mkdir(exist_ok=True)104105 unique_name = get_unique_filename(category_folder, item.name)106 destination = category_folder / unique_name107108 try:109 shutil.move(str(item), str(destination))110 moved_counts[category] = moved_counts.get(category, 0) + 1111 print(f" ✓ {item.name} -> {category}/")112 except PermissionError:113 print(f" ✗ {item.name} - File is in use, skipped")114 except Exception as e:115 print(f" ✗ {item.name} - Error: {e}")116117 return moved_counts118119120def print_summary(moved_counts):121 """Print a summary of the organization results."""122 if not moved_counts:123 print("\nNo files were moved.")124 return125126 print("\n" + "=" * 50)127 print("ORGANIZATION COMPLETE!")128 print("=" * 50)129130 total = sum(moved_counts.values())131132 for category, count in sorted(moved_counts.items()):133 print(f" {category}: {count} file(s)")134135 print(f"\nTotal files organized: {total}")136137138def main():139 """Main entry point for the file organizer."""140 import os141142 # Default to Downloads folder143 # Adjust this path for your system144 if os.name == 'nt': # Windows145 downloads_folder = Path.home() / "Downloads"146 else: # macOS/Linux147 downloads_folder = Path.home() / "Downloads"148149 # You can also specify a custom folder150 # downloads_folder = Path("/path/to/your/folder")151152 print("=" * 50)153 print("FILE ORGANIZER")154 print("=" * 50)155156 # Run the organizer157 moved_counts = organize_folder(downloads_folder)158159 # Show results160 print_summary(moved_counts)161162163if __name__ == "__main__":164 main()
How to Run This Script
-
Save the script as
file_organizer.pyon your computer -
Open your terminal (Command Prompt on Windows, Terminal on macOS/Linux)
-
Navigate to where you saved the script:
bash1cd /path/to/script -
Run the script:
bash1python file_organizer.py -
Expected output:
Prompt================================================== FILE ORGANIZER ================================================== Organizing files in: /Users/yourname/Downloads -------------------------------------------------- ✓ quarterly_report.pdf -> Documents/ ✓ vacation_photo.jpg -> Images/ ✓ meeting_recording.mp4 -> Videos/ ✓ project_backup.zip -> Archives/ ✓ script.py -> Code/ ================================================== ORGANIZATION COMPLETE! ================================================== Archives: 1 file(s) Code: 1 file(s) Documents: 1 file(s) Images: 1 file(s) Videos: 1 file(s) Total files organized: 5
Customization Options
Organize a Different Folder
Change the folder path in the main() function:
1downloads_folder = Path("/path/to/any/folder")
Add New File Categories
Add entries to the FILE_CATEGORIES dictionary:
1FILE_CATEGORIES = {2 # ... existing categories ...3 "Fonts": [".ttf", ".otf", ".woff", ".woff2"],4 "3D Models": [".obj", ".fbx", ".stl", ".blend"],5}
Organize by Date Instead
Modify the category logic to use file dates:
1from datetime import datetime23def get_date_category(file_path):4 """Organize by month and year."""5 mod_time = file_path.stat().st_mtime6 date = datetime.fromtimestamp(mod_time)7 return date.strftime("%Y-%m") # Returns "2025-11"
Skip Certain Files
Add file patterns to skip:
1SKIP_PATTERNS = ['.crdownload', '.part', '.tmp']23# In the organize_folder function:4if any(item.suffix.lower() == pattern for pattern in SKIP_PATTERNS):5 continue
Common Issues & Solutions
| Issue | Solution |
|---|---|
| "Permission denied" error | Close any programs using the files, or run as administrator |
| Files not moving | Check that the source path is correct and exists |
| Wrong category assigned | Add the extension to the correct category in FILE_CATEGORIES |
| Script can't find Downloads | Verify the path matches your system (check Windows vs Mac paths) |
| Duplicate handling not working | Ensure you have write permissions in the destination folder |
Taking It Further
Auto-Run on Schedule
Windows Task Scheduler:
- Open Task Scheduler
- Create Basic Task
- Set trigger (daily, at startup, etc.)
- Action: Start a program
- Program:
python - Arguments:
C:\path\to\file_organizer.py
macOS/Linux (cron):
1# Run every day at 9 AM20 9 * * * /usr/bin/python3 /path/to/file_organizer.py
Add Logging
Track what's been organized over time:
1import logging23logging.basicConfig(4 filename='organizer.log',5 level=logging.INFO,6 format='%(asctime)s - %(message)s'7)89# Replace print statements with:10logging.info(f"Moved: {item.name} -> {category}/")
Create an Undo Feature
Save a manifest of moves to reverse them if needed:
1import json23moves = []45# After each successful move:6moves.append({7 "original": str(item),8 "new": str(destination)9})1011# Save at the end:12with open("last_organization.json", "w") as f:13 json.dump(moves, f, indent=2)
Conclusion
You've just built a practical Python tool that solves a real problem. Every time your Downloads folder gets cluttered, you're one command away from perfect organization.
The beauty of this script is its simplicity—it uses only Python's built-in modules, handles edge cases gracefully, and is easy to customize for your specific needs.
Start with the basic version, then modify it as you learn what works best for your workflow. Maybe you want different categories, or date-based organization, or automatic scheduling. The foundation is here—make it yours.
Your Downloads folder will never be the same.
Sponsored Content
Interested in advertising? Reach automation professionals through our platform.
