Skip to content
Foxipa

Suggest an edit

Tell us what should be corrected, clarified, or improved. Submission will be connected to Foxipa’s contribution service later.

No information is sent anywhere yet. Your suggestion is only prepared in your browser.

Learning

High-Level File Operations with shutil

Copy files and directory trees, move and remove paths carefully, inspect disk space, and work with archives using Python’s shutil module.

Levels: Intermediate ~30 min read

Intermediate

Python’s shutil module provides high-level operations for copying files and directory trees, moving paths, removing directory trees, checking disk space, and creating or extracting archives. It complements pathlib, which represents and inspects paths, and File I/O, which reads and writes file contents.

Choose the right filesystem tool

For Python 3.14 and later, pathlib also has Path.copy(), Path.copy_into(), Path.move(), and Path.move_into() for path-oriented copy and move operations. This lesson uses shutil operations that can also be run on Python 3.13, so the examples are locally verifiable. shutil remains useful for configurable directory-tree copies, recursive removal, disk usage, and archive helpers. Use the API your supported Python version provides, and do not assume a copy preserves every kind of filesystem metadata.

Copy files and understand metadata

copyfile(source, destination) copies file contents to the exact destination filename. copy(source, destination) also copies permission mode and allows destination to be a directory. copy2() attempts to preserve additional metadata such as timestamps, but no copy function can preserve every platform-specific attribute. Existing destination files may be replaced, so choose the destination deliberately.

Interactive Runnable example
Edit

Ready to run.

Copy directory trees with exclusions

copytree() copies a directory and its descendants. By default, the destination must not already exist. Pass ignore=ignore_patterns(...) to skip names that match shell-style filename patterns at each visited directory. If dirs_exist_ok=True is used, files at matching destination paths can be overwritten; set it only when that behavior is intended.

Interactive Runnable example
Edit

Ready to run.

Move files or directories

shutil.move() moves a file or directory and returns the resulting destination path. A move on the same filesystem normally uses a rename operation. If that cannot work, such as when moving across filesystems, shutil may copy the data and then remove the source. Do not assume the operation is atomic across filesystems. Python 3.14+ also provides Path.move() for path-oriented moves.

Interactive Runnable example
Edit

Ready to run.

Remove a directory tree deliberately

rmtree() removes a directory and its contents, so using the wrong path can destroy valuable data. Restrict removal to a path your program created or has explicitly validated. Symlink-attack resistance depends on platform capabilities; check rmtree.avoids_symlink_attacks when that property matters. Do not silence removal errors without a clear recovery policy.

Interactive Runnable example
Edit

Ready to run.

Inspect available disk space

disk_usage(path) returns total, used, and free space in bytes for the filesystem containing a file or directory. These values depend on the mounted filesystem and can change while a program runs, so use them as a current measurement rather than a guarantee that a later write will succeed.

Interactive Runnable example
Edit

Ready to run.

Create and extract archives safely

make_archive() creates a supported archive from a directory tree; unpack_archive() extracts a recognized format. For tar-based archives, use the data extraction filter when appropriate. That filter reduces dangerous path and link behavior, but it does not make every untrusted archive harmless: inspect its contents and choose a controlled destination. The filter parameter is not accepted for ZIP archives. More specialized zipfile and tarfile operations belong to their own APIs.

Interactive Runnable example
Edit

Ready to run.

The examples use temporary workspaces so copying, moving, deleting, and archive extraction never touch a learner’s real project files. Start by inspecting the source and destination paths, then use the narrowest operation that fits the task.

Quick check

Which operation copies file contents to an exact destination filename without attempting to copy permission bits or other metadata?

from pathlib import Path
from tempfile import TemporaryDirectory
import shutil

with TemporaryDirectory() as folder:
    root = Path(folder)
    source = root / "source.txt"
    destination = root / "copy.txt"
    source.write_text("hello", encoding="utf-8")
    
    assert destination.read_text(encoding="utf-8") == "hello"
    print(destination.exists())

Quick check

Which call copies a directory tree while skipping entries whose names match `*.tmp`?

from pathlib import Path
import shutil
from tempfile import TemporaryDirectory

with TemporaryDirectory() as folder:
    root = Path(folder)
    source = root / "source"
    source.mkdir()
    (source / "keep.txt").write_text("keep", encoding="utf-8")
    (source / "skip.tmp").write_text("skip", encoding="utf-8")
    destination = root / "backup"
    
    assert (destination / "keep.txt").exists()
    assert not (destination / "skip.tmp").exists()
    print("copy filtered")

Quick check

A temporary build directory contains nested files. Which function removes the directory tree rather than requiring the directory to be empty?

from pathlib import Path
import shutil
from tempfile import TemporaryDirectory

with TemporaryDirectory() as folder:
    workspace = Path(folder) / "build"
    (workspace / "cache").mkdir(parents=True)
    (workspace / "cache" / "temp.txt").write_text("remove", encoding="utf-8")
    shutil.(workspace)
    assert not workspace.exists()
    print("removed")

Quick check

Which attribute reports currently available disk space in bytes?

import shutil
from tempfile import TemporaryDirectory

with TemporaryDirectory() as folder:
    usage = shutil.disk_usage(folder)
    print(usage.)
    assert usage.free >= 0
    print(usage.total > 0)

Quick check

When extracting a tar-based archive with unpack_archive(), which filter is the documented safer choice for ordinary data files?

from pathlib import Path
import shutil
from tempfile import TemporaryDirectory

with TemporaryDirectory() as folder:
    root = Path(folder)
    project = root / "project"
    project.mkdir()
    (project / "note.txt").write_text("safe data", encoding="utf-8")
    archive = shutil.make_archive(str(root / "snapshot"), "gztar", root_dir=str(project))
    destination = root / "restored"
    destination.mkdir()
    shutil.unpack_archive(archive, destination, )
    assert (destination / "note.txt").read_text(encoding="utf-8") == "safe data"
    print("restored")
Was this page helpful?

Mark this learning resource complete to track your learning progress.