AutomateMyJob
Back to BlogPython Automation

Automatically Organize Your Downloads Folder with Python

Alex Rodriguez12 min read

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 pathlib module 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:

  1. Scans your Downloads folder
  2. Identifies each file's type by extension
  3. Creates organized subfolders (Documents, Images, Videos, etc.)
  4. Moves each file to its appropriate folder
  5. 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:

python
1# Define file categories and their extensions
2FILE_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:

python
1def get_category(file_extension):
2    """
3    Determine which category a file belongs to based on its extension.
4    
5    Args:
6        file_extension: The file extension (e.g., '.pdf')
7    
8    Returns:
9        The category name (e.g., 'Documents') or 'Other' if not recognized
10    """
11    # Convert to lowercase for consistent matching
12    ext = file_extension.lower()
13    
14    # Search through categories for a match
15    for category, extensions in FILE_CATEGORIES.items():
16        if ext in extensions:
17            return category
18    
19    # If no match found, put in 'Other' folder
20    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:

python
1def get_unique_filename(destination_folder, filename):
2    """
3    Generate a unique filename if the file already exists.
4    
5    Args:
6        destination_folder: Path object for the destination
7        filename: Original filename
8    
9    Returns:
10        A unique filename (original or with a number suffix)
11    """
12    from pathlib import Path
13    
14    destination = destination_folder / filename
15    
16    # If file doesn't exist, use original name
17    if not destination.exists():
18        return filename
19    
20    # Split filename into name and extension
21    stem = Path(filename).stem  # 'report' from 'report.pdf'
22    suffix = Path(filename).suffix  # '.pdf'
23    
24    # Try adding numbers until we find a unique name
25    counter = 1
26    while True:
27        new_filename = f"{stem}_{counter}{suffix}"
28        if not (destination_folder / new_filename).exists():
29            return new_filename
30        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:

python
1def organize_folder(source_folder):
2    """
3    Organize all files in the source folder into categorized subfolders.
4    
5    Args:
6        source_folder: Path to the folder to organize (e.g., Downloads)
7    
8    Returns:
9        Dictionary with counts of files moved per category
10    """
11    from pathlib import Path
12    import shutil
13    
14    source = Path(source_folder)
15    
16    # Verify the folder exists
17    if not source.exists():
18        print(f"Error: Folder '{source_folder}' does not exist!")
19        return {}
20    
21    # Track how many files we move
22    moved_counts = {}
23    
24    # Process each file in the folder
25    for item in source.iterdir():
26        # Skip directories - we only want files
27        if item.is_dir():
28            continue
29        
30        # Skip hidden files (starting with .)
31        if item.name.startswith('.'):
32            continue
33        
34        # Determine the category for this file
35        category = get_category(item.suffix)
36        
37        # Create the category folder if it doesn't exist
38        category_folder = source / category
39        category_folder.mkdir(exist_ok=True)
40        
41        # Get a unique filename to avoid overwriting
42        unique_name = get_unique_filename(category_folder, item.name)
43        destination = category_folder / unique_name
44        
45        # Move the file
46        try:
47            shutil.move(str(item), str(destination))
48            
49            # Update our count
50            moved_counts[category] = moved_counts.get(category, 0) + 1
51            print(f"Moved: {item.name} -> {category}/{unique_name}")
52            
53        except Exception as e:
54            print(f"Error moving {item.name}: {e}")
55    
56    return moved_counts

The Complete Script

python
1#!/usr/bin/env python3
2"""
3File Organizer - Automatically sort files into categorized folders.
4Author: Alex Rodriguez
5
6This script organizes files in a folder (like Downloads) by moving them
7into subfolders based on their file type (Documents, Images, Videos, etc.).
8"""
9
10import shutil
11from pathlib import Path
12
13
14# Define file categories and their extensions
15FILE_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}
24
25
26def get_category(file_extension):
27    """
28    Determine which category a file belongs to based on its extension.
29    
30    Args:
31        file_extension: The file extension (e.g., '.pdf')
32    
33    Returns:
34        The category name (e.g., 'Documents') or 'Other' if not recognized
35    """
36    ext = file_extension.lower()
37    
38    for category, extensions in FILE_CATEGORIES.items():
39        if ext in extensions:
40            return category
41    
42    return "Other"
43
44
45def get_unique_filename(destination_folder, filename):
46    """
47    Generate a unique filename if the file already exists.
48    
49    Args:
50        destination_folder: Path object for the destination
51        filename: Original filename
52    
53    Returns:
54        A unique filename (original or with a number suffix)
55    """
56    destination = destination_folder / filename
57    
58    if not destination.exists():
59        return filename
60    
61    stem = Path(filename).stem
62    suffix = Path(filename).suffix
63    
64    counter = 1
65    while True:
66        new_filename = f"{stem}_{counter}{suffix}"
67        if not (destination_folder / new_filename).exists():
68            return new_filename
69        counter += 1
70
71
72def organize_folder(source_folder):
73    """
74    Organize all files in the source folder into categorized subfolders.
75    
76    Args:
77        source_folder: Path to the folder to organize (e.g., Downloads)
78    
79    Returns:
80        Dictionary with counts of files moved per category
81    """
82    source = Path(source_folder)
83    
84    if not source.exists():
85        print(f"Error: Folder '{source_folder}' does not exist!")
86        return {}
87    
88    print(f"\nOrganizing files in: {source}")
89    print("-" * 50)
90    
91    moved_counts = {}
92    
93    for item in source.iterdir():
94        if item.is_dir():
95            continue
96        
97        if item.name.startswith('.'):
98            continue
99        
100        category = get_category(item.suffix)
101        
102        category_folder = source / category
103        category_folder.mkdir(exist_ok=True)
104        
105        unique_name = get_unique_filename(category_folder, item.name)
106        destination = category_folder / unique_name
107        
108        try:
109            shutil.move(str(item), str(destination))
110            moved_counts[category] = moved_counts.get(category, 0) + 1
111            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}")
116    
117    return moved_counts
118
119
120def print_summary(moved_counts):
121    """Print a summary of the organization results."""
122    if not moved_counts:
123        print("\nNo files were moved.")
124        return
125    
126    print("\n" + "=" * 50)
127    print("ORGANIZATION COMPLETE!")
128    print("=" * 50)
129    
130    total = sum(moved_counts.values())
131    
132    for category, count in sorted(moved_counts.items()):
133        print(f"  {category}: {count} file(s)")
134    
135    print(f"\nTotal files organized: {total}")
136
137
138def main():
139    """Main entry point for the file organizer."""
140    import os
141    
142    # Default to Downloads folder
143    # Adjust this path for your system
144    if os.name == 'nt':  # Windows
145        downloads_folder = Path.home() / "Downloads"
146    else:  # macOS/Linux
147        downloads_folder = Path.home() / "Downloads"
148    
149    # You can also specify a custom folder
150    # downloads_folder = Path("/path/to/your/folder")
151    
152    print("=" * 50)
153    print("FILE ORGANIZER")
154    print("=" * 50)
155    
156    # Run the organizer
157    moved_counts = organize_folder(downloads_folder)
158    
159    # Show results
160    print_summary(moved_counts)
161
162
163if __name__ == "__main__":
164    main()

How to Run This Script

  1. Save the script as file_organizer.py on your computer

  2. Open your terminal (Command Prompt on Windows, Terminal on macOS/Linux)

  3. Navigate to where you saved the script:

    bash
    1cd /path/to/script
  4. Run the script:

    bash
    1python file_organizer.py
  5. 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:

python
1downloads_folder = Path("/path/to/any/folder")

Add New File Categories

Add entries to the FILE_CATEGORIES dictionary:

python
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:

python
1from datetime import datetime
2
3def get_date_category(file_path):
4    """Organize by month and year."""
5    mod_time = file_path.stat().st_mtime
6    date = datetime.fromtimestamp(mod_time)
7    return date.strftime("%Y-%m")  # Returns "2025-11"

Skip Certain Files

Add file patterns to skip:

python
1SKIP_PATTERNS = ['.crdownload', '.part', '.tmp']
2
3# In the organize_folder function:
4if any(item.suffix.lower() == pattern for pattern in SKIP_PATTERNS):
5    continue

Common Issues & Solutions

IssueSolution
"Permission denied" errorClose any programs using the files, or run as administrator
Files not movingCheck that the source path is correct and exists
Wrong category assignedAdd the extension to the correct category in FILE_CATEGORIES
Script can't find DownloadsVerify the path matches your system (check Windows vs Mac paths)
Duplicate handling not workingEnsure you have write permissions in the destination folder

Taking It Further

Auto-Run on Schedule

Windows Task Scheduler:

  1. Open Task Scheduler
  2. Create Basic Task
  3. Set trigger (daily, at startup, etc.)
  4. Action: Start a program
  5. Program: python
  6. Arguments: C:\path\to\file_organizer.py

macOS/Linux (cron):

bash
1# Run every day at 9 AM
20 9 * * * /usr/bin/python3 /path/to/file_organizer.py

Add Logging

Track what's been organized over time:

python
1import logging
2
3logging.basicConfig(
4    filename='organizer.log',
5    level=logging.INFO,
6    format='%(asctime)s - %(message)s'
7)
8
9# 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:

python
1import json
2
3moves = []
4
5# After each successful move:
6moves.append({
7    "original": str(item),
8    "new": str(destination)
9})
10
11# 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.

Share this article