How to Log File Movements into a CSV Report with Python

Often in Python, you may want to organize your folders automatically — moving files into subfolders like Images, Documents, or Videos.
But what if you also want to keep a detailed record of every file moved, including the original path, new location, and timestamp?
This tutorial will show you how to build a Python script that both organizes your files and logs every movement to a CSV file for easy tracking.
1. Set Up Your Environment
Make ensure you have Python installed. If not, get it from python.org. We’ll be using Python’s built-in os
, shutil
, csv
, and datetime
modules.
2. Import Required Modules
Start by importing the libraries we’ll use. Python has built-in modules that handle file operations and CSV logging.
1
2
3
4
import os
import shutil
import csv
from datetime import datetime
os
lets us work with file paths and folders.shutil
moves files between directories.csv
helps write and read CSV logs.datetime
gives or provides timestamps for each logged operation
3. Setting Up the CSV Logger
Before moving any files, we can create (or reuse) a CSV file where Python will store every move.
Here’s a helper function to prepare it:
1
2
3
4
5
6
7
8
9
10
11
12
13
def setup_csv_logger(log_file_path):
"""
Sets up the CSV file for logging. Writes headers if the file is new.
"""
fieldnames = ['Timestamp', 'Original Path', 'New Path', 'File Name', 'Category', 'Status']
file_exists = os.path.isfile(log_file_path)
with open(log_file_path, 'a', newline='') as csvfile:
writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
if not file_exists:
writer.writeheader() # Write header only if file is new
return log_file_path
You can use this to ensure your CSV has column headers if it’s being created for the first time. If the file already exists, Python will simply append new rows to it.
4. Logging Each File Movement
Next, we’ll create a function that writes each file’s movement into the CSV log.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
def log_movement(log_file_path, original_path, new_path, file_name, category, status="Success"):
"""
Logs a file movement or status into the CSV report.
"""
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
fieldnames = ['Timestamp', 'Original Path', 'New Path', 'File Name', 'Category', 'Status']
with open(log_file_path, 'a', newline='') as csvfile:
writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
writer.writerow({
'Timestamp': timestamp,
'Original Path': original_path,
'New Path': new_path,
'File Name': file_name,
'Category': category,
'Status': status
})
Each time a file moves, this function records when it happened, where it came from, where it went, and whether it succeeded.
5. Organizing Files by Type
Now, let’s define the main function that organizes the files and logs each step.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
def organize_files_with_logging(directory_path, log_file_path):
"""
Organizes files in the given directory into subfolders based on file type
and logs all movements to a CSV file.
"""
setup_csv_logger(log_file_path) # Ensure log file and headers are ready
file_categories = {
"Images": ['.jpg', '.jpeg', '.png', '.gif', '.bmp', '.tiff', '.webp'],
"Videos": ['.mp4', '.mov', '.avi', '.mkv', '.flv', '.wmv'],
"Audio": ['.mp3', '.wav', '.aac', '.flac', '.ogg'],
"Documents": ['.pdf', '.doc', '.docx', '.xls', '.xlsx', '.ppt', '.pptx', '.txt', '.rtf'],
"Archives": ['.zip', '.rar', '.7z', '.tar', '.gz'],
"Executables": ['.exe', '.dmg', '.app', '.bat'],
"Code": ['.py', '.js', '.html', '.css', '.php', '.java', '.cpp', '.c', '.json'],
"Design": ['.psd', '.ai', '.sketch', '.xd'],
"Spreadsheets": ['.csv', '.ods'],
}
other_folder_name = "Others"
other_folder_path = os.path.join(directory_path, other_folder_name)
os.makedirs(other_folder_path, exist_ok=True)
print(f"Organizing files in: {directory_path} and logging to {log_file_path}")
# Create a list of items to process to avoid issues if files are moved
# while iterating over os.listdir.
items_to_process = list(os.listdir(directory_path))
for item in items_to_process:
original_item_path = os.path.join(directory_path, item)
if not os.path.isfile(original_item_path):
# Skip directories or items that are no longer files (e.g. moved by previous iteration)
if os.path.isdir(original_item_path) and (item in file_categories.keys() or item == other_folder_name):
# Skip the category folders we are creating or the 'Others' folder
continue
print(f"Skipping non-file or already processed item: '{item}'")
continue
file_extension = os.path.splitext(item)[1].lower()
moved = False
target_category = "Uncategorized" # Default for logging
for category, extensions in file_categories.items():
if file_extension in extensions:
target_folder_path = os.path.join(directory_path, category)
os.makedirs(target_folder_path, exist_ok=True)
destination_path = os.path.join(target_folder_path, item)
# Check if a file with the same name already exists in the destination
if os.path.exists(destination_path):
status_message = f"File already exists in '{category}/'. Skipping."
print(f"Warning: '{item}' - {status_message}")
log_movement(log_file_path, original_item_path, destination_path, item, category, status_message)
moved = True # Consider it 'handled'
break # Move to next item
try:
shutil.move(original_item_path, destination_path)
print(f"Moved '{item}' to '{category}/'")
log_movement(log_file_path, original_item_path, destination_path, item, category, "Success")
moved = True
target_category = category
break # Move to next item
except shutil.Error as e:
status_message = f"Error moving '{item}': {e}"
print(status_message)
log_movement(log_file_path, original_item_path, destination_path, item, category, status_message)
moved = True # Prevent it from going to 'Others' if an error occurred in a specific category
break # Move to next item
if not moved:
# If no category matched or an error occurred that prevented definitive move
destination_path = os.path.join(other_folder_path, item)
# Check if a file with the same name already exists in 'Others'
if os.path.exists(destination_path):
status_message = f"File already exists in '{other_folder_name}/'. Skipping."
print(f"Warning: '{item}' - {status_message}")
log_movement(log_file_path, original_item_path, destination_path, item, other_folder_name, status_message)
else:
try:
shutil.move(original_item_path, destination_path)
print(f"Moved '{item}' to '{other_folder_name}/'")
log_movement(log_file_path, original_item_path, destination_path, item, other_folder_name, "Success")
except shutil.Error as e:
status_message = f"Error moving '{item}': {e}"
print(status_message)
log_movement(log_file_path, original_item_path, destination_path, item, other_folder_name, status_message)
print("\nFile organization and logging complete!")
This is where Python does the heavy lifting:
- It loops through each file, identifies its type, moves it, and records the action in your CSV log.
- Files that don’t fit any category go into an Others folder.
6. Running the Script
Here’s the final part — where you can test the script:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
if __name__ == "__main__":
# !!! IMPORTANT: Replace this with the actual path you want to organize !!!
# It's recommended to test on a dedicated test folder first.
target_directory = os.path.expanduser("~/Desktop/test_folder_for_logging")
# Define the path for your log file.
# It's good practice to place it outside the target_directory
# or ensure it's not moved by the script itself.
log_file = os.path.join(os.path.expanduser("~"), "file_movement_log.csv")
# Ensure the target directory exists for testing
os.makedirs(target_directory, exist_ok=True)
# Create some dummy files for testing
# You might want to remove these lines after initial testing
dummy_files = [
"document.pdf", "image.jpg", "video.mp4", "audio.mp3",
"archive.zip", "script.py", "presentation.pptx", "report.txt",
"unknown_file.xyz", "another_image.png", "old_doc.doc"
]
for filename in dummy_files:
with open(os.path.join(target_directory, filename), 'w') as f:
f.write("dummy content")
print("Dummy files created in test folder for demonstration.")
organize_files_with_logging(target_directory, log_file)
You can run this script from your terminal:
1
python organizer_with_log.py
When it finishes, open your file_movement_log.csv file. You’ll see a clean, timestamped record of every file that was moved.
Sample CSV Output
Your log file will contain structured data like this:
Timestamp | Original Path | New Path | File Name | Category | Status |
---|---|---|---|---|---|
2024-01-15 10:30:15 | /home/user/Desktop/report.pdf |
/home/user/Desktop/Documents/report.pdf |
report.pdf |
Documents | Success |
2024-01-15 10:30:16 | /home/user/Desktop/photo.jpg |
/home/user/Desktop/Images/photo.jpg |
photo.jpg |
Images | Success |
2024-01-15 10:30:17 | /home/user/Desktop/data.xlsx |
/home/user/Desktop/Spreadsheets/data.xlsx |
data.xlsx |
Spreadsheets | Success |
2024-01-15 10:30:18 | /home/user/Desktop/unknown.xyz |
/home/user/Desktop/Others/unknown.xyz |
unknown.xyz |
Others | Success |
This structured format makes it easy to audit file movements, track organization history, and identify any issues that occurred during the automation process.
Conclusion
This tutorial showed you how to:
- Automatically organize files in Python by type.
- Log every file movement with a timestamp and status in a CSV file.
- Keep a clean, trackable record of your automation process.
You can use this approach to audit, debug, or simply monitor your automated file operations — all with a single Python script.
You’ve successfully enhanced your Python file organization script to generate a detailed CSV log of all file movements. This adds a crucial layer of accountability and transparency to your automated tasks. Whether for personal record-keeping, professional auditing, or debugging, having a log of file system changes is invaluable.
Additional Resources
The following tutorials explain how to perform other common file-handling tasks in Python: