Concepts / Working with Files and Directories

Working with Files and Directories

The files and directories to be backed up are specified in a list.

  • Programming

What Does It Mean to Back Up Files and Directories?

When you create a backup system, you need to decide which files and directories matter enough to save. This decision is not made automatically—you explicitly specify what to back up. The core idea is simple: you maintain a list of source files and directories, choose a target location where backups will be stored, and then create an archive (often a zip file) containing everything on that list. Understanding how to organize and specify these sources is the foundation of any reliable backup workflow.

The Three Core Components of a Backup Specification

Every backup system has three essential parts that work together. First, you define a source list—a collection of file paths and directory paths that you want to preserve. Second, you specify a target directory—the location on your disk where all backup archives will be stored. Third, you generate a unique name for each backup archive, typically using the current date and time, so you can distinguish between backups made at different moments. These three components form the backbone of how files and directories are organized for backup.

specifiesstores ingeneratesincludesincludesincludescontainsBackup SystemSource ListFiles and directories toback updocuments.txt2024-01-15_14-30-45.zipTarget DirectoryWhere backups are storedconfig.iniArchive NameTimestamp + .zip extensionphotos/
How are files organized within directories, and what does a nested folder structure look like when preparing for backup?

Specifying the Source List

The source list is where you declare exactly which files and directories you want to back up. In Python, this is typically a list of strings, where each string is a file path or directory path. You create this list explicitly in your code, deciding what matters enough to preserve. For example, you might include configuration files, document folders, and database files, but exclude temporary files or cache directories. The source list is not generated automatically—you write it based on what you know your system needs to protect.

The source list is a Python list that you define in your backup script. Each element is a string representing a file path or directory path that should be included in the backup.

The Target Directory and Archive Naming

The target directory is a single location on your disk where all backup archives will be stored. You specify this as a string path in a variable (commonly named target_dir). Once you have chosen this location, every backup archive created by your script will be placed there. The name of each archive is generated using the current date and time, which you obtain using the time.strftime() function. This ensures that each backup has a unique, timestamped name, making it easy to identify when each backup was created. The archive is always given a .zip extension so it can be recognized as a compressed archive.

The target_dir variable holds the path where backups are stored. The archive name is generated from the current date and time using time.strftime(), and always ends with .zip.

Importing Modules and Setting Up the Backup Specification

To work with files, directories, and timestamps, you need to import the os and time modules at the beginning of your script. The os module provides functions to interact with the file system, and the time module gives you access to time-related functions like strftime(), which formats the current time into a string. Once these modules are imported, you can define your source list and target directory, and then generate a timestamped archive name. This setup is the first step in any backup workflow.

python

How Timestamps Create Unique Archive Names

Generating a Timestamped Backup Archive Name

You want to create a backup archive that is automatically named with the current date and time so that multiple backups can be stored without overwriting each other. How does time.strftime() help you achieve this?

Import the time module: The time module provides the strftime() function, which formats time into a human-readable string.

Call time.strftime() with a format string: The format string '%Y-%m-%d_%H-%M-%S' tells strftime() to produce a string like '2024-01-15_14-30-45', where %Y is the 4-digit year, %m is the 2-digit month, %d is the 2-digit day, %H is the hour, %M is the minute, and %S is the second.

Append the .zip extension: By concatenating '.zip' to the timestamp string, you create a complete archive name like '2024-01-15_14-30-45.zip'.

Combine with target directory: Use os.path.join() to combine the target directory path with the archive name, creating the full path where the archive will be stored.

Each time the backup script runs, it generates a unique archive name based on the exact moment it ran. For example, a backup at 2:30:45 PM on January 15, 2024 produces '2024-01-15_14-30-45.zip', and a backup at 3:15:20 PM the same day produces '2024-01-15_15-15-20.zip'. This ensures backups never overwrite each other.

Extending the Source List Dynamically

Sometimes you want to allow users to add extra files and directories to the backup at runtime, rather than hard-coding them into the script. You can do this by accepting command-line arguments and adding them to your source list using the extend() method. The sys.argv list contains all command-line arguments passed to your script. By reading from sys.argv and extending your source list, you make your backup script more flexible. For example, a user could run the script and specify additional directories to back up without editing the code.

The sys.argv list contains command-line arguments. You can use the list.extend() method to add these arguments to your source list, making your backup specification dynamic.

Adding Command-Line Arguments to the Source List

python

If a user runs this script from the command line like python backup.py /home/user/videos /home/user/music, then sys.argv[1:] will be ['/home/user/videos', '/home/user/music']. The extend() method adds both of these paths to the source list. Now the backup will include the base files plus the two extra directories specified by the user.

Common Mistakes When Specifying Files and Directories

  • Forgetting to import os and time modules

    Without importing time, the code will raise a NameError because time is not defined. The os module is needed for path operations like os.path.join().

    Fix: Always begin your script with 'import os' and 'import time' before using any functions from these modules.

  • Using incorrect file paths that do not exist on the system

    If a path in the source list does not exist, the backup process will fail or produce incomplete results. The backup system cannot back up files that are not there.

    Fix: Verify that all paths in your source list actually exist on your system before running the backup. Use absolute paths or test paths with os.path.exists() first.

  • Mixing relative and absolute paths without understanding the difference

    Relative paths like 'documents' and './photos' depend on the current working directory when the script runs. This can lead to backing up the wrong files if the script is run from a different directory.

    Fix: Use absolute paths (starting with /) consistently throughout your source list, or ensure you understand and control the current working directory.

  • Not checking if the target directory exists before creating archives there

    If target_dir does not exist, the backup will fail when trying to write the archive file to that location.

    Fix: Before running the backup, verify that target_dir exists. You can use os.path.exists() to check, or create it with os.makedirs() if needed.

  • Assuming sys.argv[0] is a file path to back up

    sys.argv[0] is the name of the script itself, not a file to back up. Including it in the source list will try to back up the script, which is usually not intended.

    Fix: Always use sys.argv[1:] when extending the source list with command-line arguments, skipping the script name at index 0.

Visualizing Which Files Are Included in Your Backup

When you create a source list, you are making an explicit decision about which files and directories will be backed up and which will not. It helps to visualize this mapping: each entry in your source list corresponds to a real location on your disk. Understanding this mapping prevents you from accidentally leaving out important files or including unnecessary ones.

maps tomaps tomaps tosource[0]/home/user/documentsDisk Location:documents/Contains .txt, .pdf filessource[1]/home/user/photosDisk Location:photos/Contains .jpg, .png filessource[2]/etc/config.iniDisk Location:config.iniSingle configuration file
Which files and directories are included in the backup list, and how do they map to actual locations on disk?

Putting It All Together: A Complete Backup Specification

Setting Up a Complete Backup Specification

You need to create a backup script that backs up three directories (/home/user/documents, /home/user/photos, /home/user/projects), stores the backup in /backups, and allows users to add extra directories from the command line. The archive should be named with a timestamp.

Import required modules: Import os, time, and sys at the top of your script. These provide file system operations, timestamp generation, and command-line argument access.

Define the base source list: Create a list containing the three directories you always want to back up: ['/home/user/documents', '/home/user/photos', '/home/user/projects'].

Add command-line arguments to the source list: Use source.extend(sys.argv[1:]) to add any extra directories the user specifies when running the script.

Set the target directory: Assign target_dir = '/backups'. This is where all backup archives will be stored.

Generate the timestamped archive name: Use archive_name = time.strftime('%Y-%m-%d_%H-%M-%S') + '.zip' to create a unique name based on the current date and time.

Construct the full archive path: Use archive_path = os.path.join(target_dir, archive_name) to create the complete path where the archive will be written.

Your backup specification is now complete. The source list contains the three base directories plus any extras provided by the user. The target directory is set to /backups, and the archive will be named something like '2024-01-15_14-30-45.zip'. When the backup process runs, it will compress all files in the source list into this archive and store it in the target directory.

Best Practices for Organizing Your Backup Specification

  • Use absolute paths in your source list to avoid confusion about which files are being backed up relative to the current working directory.
  • Keep your source list in a separate configuration section at the top of your script, making it easy to modify without touching the backup logic.
  • Always verify that paths in your source list exist before running the backup. Use os.path.exists() to check.
  • Ensure your target directory exists and has sufficient disk space before creating archives. Consider using os.makedirs() to create it if needed.
  • Use a consistent timestamp format (like '%Y-%m-%d_%H-%M-%S') so backup archives are sorted chronologically by name.
  • Document which files and directories are included in your backup, so you know what is protected and what is not.
  • Test your backup specification on a small set of files first before backing up large directories.

Practice: Design Your Own Backup Specification

MEDIUM

Write out the Python code for a backup specification that includes the following: a base source list containing /home/user/important_data and /home/user/config, a target directory of /home/backups, and the ability to accept additional directories from the command line. Generate a timestamped archive name. Do not write the actual backup logic—just the specification part (imports, source list, target directory, and archive name).

Hints
  • Remember to import os, time, and sys at the top.
  • Define source as a list with the two base paths.
  • Use source.extend(sys.argv[1:]) to add command-line arguments.
  • Use time.strftime() with a format string to generate the timestamp.
  • Use os.path.join() to combine the target directory and archive name.

Summary

Working with files and directories in a backup system requires three key components: a source list that specifies which files and directories to back up, a target directory where backup archives are stored, and a timestamped archive name that ensures each backup is unique. You import the os and time modules to access file system operations and timestamp generation. The source list is a Python list of strings, each representing a file or directory path. The target directory is a single location on disk. The archive name is generated using time.strftime() and always includes a .zip extension. You can make your backup specification more flexible by using sys.argv to accept additional directories from the command line and the extend() method to add them to your source list. Understanding this specification is the foundation for building reliable backup systems.

Key Takeaways

  • A backup specification consists of three components: a source list (files and directories to back up), a target directory (where backups are stored), and a timestamped archive name (generated from the current date and time).
  • The os and time modules must be imported to work with file paths and generate timestamps using time.strftime().
  • The source list is a Python list of strings, where each string is an absolute path to a file or directory.
  • Command-line arguments can be added to the source list dynamically using sys.argv and the list.extend() method.
  • Archive names should use a consistent timestamp format like '%Y-%m-%d_%H-%M-%S' to ensure uniqueness and chronological sorting.