Python Automating Files

In the last lesson you learned Error Handling in APIs. There Python talked to the outside world over the network. Now we bring the work back to your own machine. Think of the folder where downloads pile up. Screenshots, invoices, zip files, and photos, all mixed together. You could clean it by hand. You drag files around one by one. Or you could write a few lines of Python once. Then let it do the boring part for you, every time.

๐Ÿค” Why automate file jobs?

Here is the pain. You have a folder with two hundred files. You need to rename them all. Or you want to move the images into one place and the PDFs into another. Doing that by clicking is slow. And you will make mistakes.

The fix is simple. Pythonโ€™s standard library can already list, rename, move, copy, and delete files for you. There is nothing extra to install. You describe the rule once. Python applies it to every file in the folder, the same way, every time.

We will use two tools that come built into Python:

  • pathlib โ€” the modern way to point at a file or folder and ask about it
  • shutil โ€” short for โ€œshell utilitiesโ€, the module that moves, copies, and deletes whole files and folders

Neither of these needs pip install. They ship with Python itself.

๐Ÿงญ Pointing at files with pathlib

Before you can rename or move a file, you have to point at it. A Path is Pythonโ€™s way of holding a location on disk. It can point at a folder or a file. You hold it as an object and ask it questions.

Here is how you point at a folder and check that it really exists.

from pathlib import Path
# Point at a folder. Nothing happens on disk yet, this is just a label.
downloads = Path("C:/Users/Alex/Downloads")
print(downloads.exists()) # True if the folder is really there
print(downloads.is_dir()) # True if it is a folder, not a file

Let me walk through it.

  • Path("...") builds a path object. It does not touch the disk. It just remembers the location.
  • .exists() asks the disk โ€œis there anything at this location?โ€ and gives back True or False.
  • .is_dir() asks โ€œis this a folder?โ€ so you know it is not a single file.

Output

True
True

Note

Use forward slashes in your paths, like "C:/Users/Alex/Downloads", even on Windows. Python handles them correctly on every system. A single backslash starts an escape code inside a string. That causes confusing bugs.

๐Ÿ“‹ Listing files in a folder

The first real job is seeing what is in a folder. The .iterdir() method walks through everything inside a folder. It hands you one path at a time.

This prints the name of every item directly inside the folder.

from pathlib import Path
folder = Path("C:/Users/Alex/Downloads")
for item in folder.iterdir():
print(item.name)

item is a full Path for each thing in the folder. item.name is just the short file name. It drops the long folder part in front.

Output

report.txt
photo1.jpg
photo2.jpg
invoice.pdf
notes.txt
setup.exe

Note

This is example output. The exact names depend on whatever is actually sitting in your folder. So yours will look different.

Often you do not want every file. You want only the .txt files, or only the images. The .glob() method takes a pattern and gives back just the matching files. The * means โ€œanythingโ€. So *.txt means โ€œany name that ends in .txtโ€.

This grabs only the text files and prints each one.

from pathlib import Path
folder = Path("C:/Users/Alex/Downloads")
for txt_file in folder.glob("*.txt"):
print(txt_file.name)

Output

report.txt
notes.txt

A Path also splits a file name into useful parts for you. This saves you from cutting strings by hand.

Attribute What it gives you For photo1.jpg
.name The full file name photo1.jpg
.stem The name without the extension photo1
.suffix The extension, with the dot .jpg
.parent The folder it lives in C:/Users/Alex/Downloads

โœ๏ธ Renaming many files at once

Now the satisfying part. Say you have a pile of text files with messy names. You want them all renamed neatly to note_1.txt, note_2.txt, and so on. By hand that is painful. In Python it is a short loop.

The .rename() method changes a fileโ€™s name or location. You give it the new full path you want.

This renames every .txt file in the folder to a clean numbered name.

from pathlib import Path
folder = Path("C:/Users/Alex/Downloads")
# enumerate gives us a counter (1, 2, 3...) alongside each file.
for number, txt_file in enumerate(folder.glob("*.txt"), start=1):
new_name = folder / f"note_{number}.txt"
txt_file.rename(new_name)
print(f"Renamed {txt_file.name} -> {new_name.name}")

Reading it line by line:

  • enumerate(..., start=1) walks the files and also counts them. It starts the count at 1.
  • folder / f"note_{number}.txt" builds the new path. The / joins a folder and a name into one path, which reads nicely.
  • .rename(new_name) does the actual rename on disk.
  • The print line gives you a record of what changed. So you can see it worked.

Output

Renamed report.txt -> note_1.txt
Renamed notes.txt -> note_2.txt

Note

That arrow and the names are example output. Your real files and counts will differ. The point is the pattern. You loop, build a new name, rename, then print what you did.

Caution

.rename() is instant and there is no undo. If a file with the new name already exists, on some systems it gets overwritten and the old one is gone. Before running a rename on real files, run it once with the .rename(...) line commented out and only the print line active. That way you see the plan first. Then you turn on the real action.

๐Ÿ“ฆ Moving and copying with shutil

pathlib is great for one folder. When you want to move or copy files between folders, shutil is the right tool. Think of shutil as the moving company. It carries whole files from one place to another. It can duplicate them too.

Function What it does
shutil.copy(src, dst) Copies a file. The original stays.
shutil.move(src, dst) Moves a file. The original is gone from the old spot.
shutil.copytree(src, dst) Copies a whole folder and everything inside it.

Here we copy one file into a backup folder. Then we move another file out of Downloads.

import shutil
from pathlib import Path
downloads = Path("C:/Users/Alex/Downloads")
backup = Path("C:/Users/Alex/Backup")
# Make the backup folder if it is not there yet.
# parents=True creates any missing folders above it.
# exist_ok=True means "do not complain if it already exists".
backup.mkdir(parents=True, exist_ok=True)
# Copy: the invoice stays in Downloads AND appears in Backup.
shutil.copy(downloads / "invoice.pdf", backup / "invoice.pdf")
# Move: the report leaves Downloads and lands in Backup.
shutil.move(str(downloads / "report.txt"), str(backup / "report.txt"))
print("Backup done.")

The new piece here is mkdir. It creates the folder you want to move things into. You need it because shutil will not invent a missing destination folder for you. After that, copy duplicates the file and move relocates it.

Output

Backup done.

Tip

shutil.move and copy accept either Path objects or plain text paths. Wrapping a Path in str(...), like str(downloads / "report.txt"), turns it into plain text. That works everywhere, which is a safe habit across Python versions.

๐Ÿ—‘๏ธ Deleting files and folders

Sometimes the boring job is cleanup. Deleting takes two different tools. It depends on whether you are removing a single file or a whole folder.

  • A single file goes away with .unlink() from pathlib.
  • A whole folder, with everything inside it, goes away with shutil.rmtree().

This deletes one leftover file. Then it removes an entire temporary folder.

import shutil
from pathlib import Path
old_file = Path("C:/Users/Alex/Downloads/setup.exe")
temp_folder = Path("C:/Users/Alex/Downloads/temp_stuff")
# Delete a single file, but only if it actually exists.
if old_file.exists():
old_file.unlink()
print(f"Deleted {old_file.name}")
# Delete a whole folder and everything in it.
if temp_folder.exists():
shutil.rmtree(temp_folder)
print(f"Removed folder {temp_folder.name}")

The if ... exists() check matters. If you try to delete something that is not there, Python raises an error and stops. Checking first keeps the program calm.

Output

Deleted setup.exe
Removed folder temp_stuff

Danger

shutil.rmtree() deletes a folder and everything inside it. There is no recycle bin and no undo. If you point it at the wrong path, that data is gone. Always print the path first and read it carefully before you let rmtree run on real files.

๐Ÿ—‚๏ธ Real example: sort files by extension

Let us put it all together. Here is the job many people actually want. You take a messy Downloads folder. Then you drop each file into a subfolder named after its type. Images go into an images folder, PDFs into a pdf folder, and so on.

The plan in plain words. Look at every file. Read its extension. Make a folder for that extension if it is missing. Then move the file in.

This script sorts a whole folder by file type.

import shutil
from pathlib import Path
downloads = Path("C:/Users/Alex/Downloads")
for item in downloads.iterdir():
# Skip folders, we only sort files.
if item.is_dir():
continue
# suffix is like ".jpg". Drop the dot and lowercase it -> "jpg".
ext = item.suffix.lower().lstrip(".")
if ext == "":
ext = "no_extension"
# The destination folder, e.g. Downloads/jpg
target_folder = downloads / ext
target_folder.mkdir(exist_ok=True)
# Move the file into its folder.
shutil.move(str(item), str(target_folder / item.name))
print(f"Moved {item.name} -> {ext}/")
print("Sorting complete.")

Walking through the important lines:

  • item.is_dir() plus continue skips folders. So we do not try to sort a folder into itself.
  • item.suffix.lower().lstrip(".") turns .JPG into a clean jpg. .lower() makes the case match, and .lstrip(".") removes the leading dot.
  • mkdir(exist_ok=True) makes the type folder. It quietly does nothing if it is already there.
  • shutil.move(...) drops the file into the right folder.

Output

Moved report.txt -> txt/
Moved photo1.jpg -> jpg/
Moved photo2.jpg -> jpg/
Moved invoice.pdf -> pdf/
Moved notes.txt -> txt/
Sorting complete.

Note

This is representative output. The files, counts, and types depend on what is in your real folder. So the exact lines will be different for you. The shape stays the same. You get one โ€œMovedโ€ line per file, then a final message.

โš ๏ธ Common Mistakes

A few traps catch people the first time they automate files.

  • Running on real files before testing. Always try your script on a throwaway test folder first. Make a few junk files, run it, then see that it did the right thing.
  • Forgetting the destination folder must exist. shutil.move and copy will not create a missing target folder for you. Call .mkdir(exist_ok=True) first.
  • Using single backslashes in Windows paths. A path like "C:\Users\Alex" breaks because \U and \A look like escape codes. Use forward slashes instead.
  • Deleting without checking. Calling .unlink() on a file that is not there crashes the script.
from pathlib import Path
f = Path("C:/Users/Alex/Downloads/maybe.txt")
# โŒ Avoid: crashes if the file is already gone
f.unlink()
# โœ… Good: check first, then delete
if f.exists():
f.unlink()

โœ… Best Practices

Small habits keep file automation safe and easy to read.

  • Do a dry run first. Print what the script would do before you let it move or delete anything. Turn on the real action only once the plan looks right.
  • Prefer pathlib over the older os.path. Building paths with / reads far more clearly than gluing strings together.
  • Keep a backup of important files before running a script that moves or deletes. A quick shutil.copytree of the whole folder costs you nothing.
  • Use clear names for paths, like downloads and backup, so anyone reading the script knows what each one points at.

๐Ÿงฉ What Youโ€™ve Learned

You can now hand the boring file jobs to Python.

  • โœ… Point at files and folders with pathlib.Path, and check them with .exists() and .is_dir()
  • โœ… List a folder with .iterdir() and filter by type with .glob("*.txt")
  • โœ… Rename many files at once in a loop using .rename()
  • โœ… Move and copy files and folders with shutil.move, shutil.copy, and shutil.copytree
  • โœ… Delete safely with .unlink() for files and shutil.rmtree() for folders
  • โœ… Build a real sorter that files everything by its extension

Check Your Knowledge

Test what you learned. Pick an answer for each question, then click Check.

  1. 1

    Which method lists every item directly inside a folder using pathlib?

    Why: Path.iterdir() walks through everything directly inside a folder, handing you one Path at a time.

  2. 2

    What does shutil.move(src, dst) do to the original file?

    Why: move relocates the file, so the original is gone from the old location; copy is the one that leaves the original in place.

  3. 3

    Why call backup.mkdir(parents=True, exist_ok=True) before moving files into a backup folder?

    Why: shutil needs the destination folder to exist; mkdir creates it, and exist_ok=True stops it from erroring when the folder already exists.

  4. 4

    Which tool removes a whole folder along with everything inside it?

    Why: shutil.rmtree() deletes a folder and all of its contents; unlink and os.remove only handle single files.

๐Ÿš€ Whatโ€™s Next?

You can sort, rename, and move files now. So let us point that automation at the files everyone dreads most. Next we make Python read and write spreadsheets for you.

Automating Excel Tasks

Share & Connect