Using Python for File Management Tasks


Working with Files

  • important because network devices interact with:
    • configuration files
    • configuration templates
    • files containing connection options
    • other script files

File Handling

  • Python has several built-in functions for handling files:
    • open(filename, mode)
      • opens a file in the specified mode
        • r for read, w for write, a for append, b for binary
    • file.read([size])
      • reads at most size bytes from the file
      • reads whole file if not specified
    • file.readline()
      • reads the next line of the file
    • file.readlines()
      • returns a list of all the lines in a file
    • file.write(string)
      • writes the string to the file and returns the number of characters written
    • file.close()
      • closes the file
def log_network_activity(device_ip, username, password, log_file):
    # Connect to the network device (assuming a function connect_to_device is defined)
    connection = connect_to_device(device_ip, username, password)
    
    # Get the network activity
    activity = connection.get_activity()
    
    # Open the log file in append mode
    file = open(log_file, 'a')
    
    # Write the activity to the file
    file.write(activity)
    
    # Close the file
    file.close()

Text vs Binary Files

  • Text files and binary files are two types of files that can be handled in Python
  • key differences:
    • Text files
      • human-readable files containing text
      • structured as sequence of lines, each containing sequence of characters
      • includes programming source code, HTML files, etc
      • opening in a text editor displays content as text
    • Binary files
      • not designed to be human-readable
      • may contain any type of data encoded in binary form for computer processing
        • e.g., images, audio files, executable files, etc.
      • opening in a text editor, appears as random special characters
  • can open both with open() function
    • mode parameter determines how file is opened
      • t for text
      • b for binary
      • e.g., rb opens for reading in binary mode
  • Python handles the encoding and decoding of text into the specific character set (e.g., UTF-8)
    • no encoding is performed for binary files
      • data is read directly
      • makes binary mode suitable for non-text files (image, executable, etc)
      • useful when need to preserve the exact bytes of the file
        • e.g., checksum operation
  • in network automation,
    • text files are often used for storing configuration commands, logs, etc.
    • binary files could be used for firmware images, packet captures, etc.

Text Files

  • steps to work with text files:
    • open a file
    • read from a file
    • write to a file
    • close a file
def read_config_commands(config_file):
    # Open the file in read mode
    file = open(config_file, 'r')
    
    # Read all lines into a list
    commands = file.readlines()
    
    # Close the file
    file.close()
    
    # Remove newline characters
    commands = [command.strip() for command in commands]
    
    return commands

Binary Files

  • same steps:
    • open a file
    • read from a file
    • write to a file
    • close a file
def read_firmware_image(firmware_file):
    # Open the file in binary read mode
    file = open(firmware_file, 'rb')
    
    # Read the entire file
    firmware_data = file.read()
    
    # Close the file
    file.close()
    
    return firmware_data

Comma Separated Values

Comma Separated Values (CSV) files are a type of text file commonly used to store tabular data.

  • each line in the file represents a row in the table
  • each value in a row is separated by commas
  • Python has a csv module to work with CSV files
    • open a file:
      • open() function with r or w modes
    • create a CSV reader or writer:
      • csv.reader() or csv.writer() function to create a reader/writer object
    • reading from a file:
      • next() function to read a row from the file
      • each row is returned as a list of strings
    • writing to a file:
      • writerow() function to write a row to the file
        • row should be a list of strings
      • .writerows() method to write multiple rows
import csv
 
def read_device_info(device_file):
    # Open the file in read mode
    file = open(device_file, 'r')
    
    # Create a CSV reader
    reader = csv.reader(file)
    
    # Read the header row
    headers = next(reader)
    
    # Read the rest of the rows
    devices = [row for row in reader]
    
    # Close the file
    file.close()
    
    return headers, devices

Reading Files

Reading Parts of a File

  • can read parts of a file using the read() method with a size argument
    • for number of bytes to read
def read_part_of_log(log_file, size):
    # Open the file in read mode
    file = open(log_file, 'r')
    
    # Read the specified number of bytes
    part_of_log = file.read(size)
    
    # Close the file
    file.close()
    
    return part_of_log

Reading Lines in a File

  • can read a single line from a file with open() function and readline() method
with open('filename.txt', 'r') as file:
    first_line = file.readline()

Writing to Files

Writing to an Existing File

  • can write to an existing file with open() with the a (append) or w (overwrite) mode
with open('filename.txt', 'a') as file:
    file.write('New line to append\n')
import os
 
with open('device_ip.txt', 'r') as file:
    device_ip = file.readline().strip()
 
response = os.system("ping -c 1 " + device_ip)
 
with open('log.txt', 'a') as file:
    if response == 0:
        file.write(device_ip + ' is up!\n')
    else:
	    file.write(device_ip + ' is down!\n')

Creating a New File

  • can create a new file with open() and x, a, or w mode
    • 'x': Creates a new file and opens it for writing
      • If the file already exists, the operation fails
    • 'a': Opens the file for writing, appending to the end of the file if it exists
    • 'w': Opens the file for writing
      • If the file exists, it is truncated
      • If the file does not exist, it is created
# 'x' mode
try:
    with open('newfile_x.txt', 'x') as file:
        file.write('Content for the new file\n')
except FileExistsError:
    print('File already exists.')
 
# 'a' mode
with open('newfile_a.txt', 'a') as file:
    file.write('Content for the new file\n')
 
# 'w' mode
with open('newfile_w.txt', 'w') as file:
    file.write('Content for the new file\n')

Example

log network device status to a new file:

import os
 
with open('device_ip.txt', 'r') as file:
    device_ip = file.readline().strip()
 
response = os.system("ping -c 1 " + device_ip)
 
try:
    with open('new_log.txt', 'x') as file:
        if response == 0:
            file.write(device_ip + ' is up!\n')
        else:
            file.write(device_ip + ' is down!\n')
except FileExistsError:
    print('Log file already exists.')
  •  script reads the IP address, pings the device, and then logs whether the device is up or down to the 'new_log.txt' file
  •  If the log file already exists, a message is printed instead of raising an error
    • done using a try-except block to catch the FileExistsError exception
    • This exception is raised when a file operation like creation or renaming fails because the target file already exists
    • this is specific to the x mode
  • 'a' and 'w' modes do not raise this exception because they are designed to work with existing files
    • 'a' mode appends to the file
    • 'w' mode truncates the file before writing
    • If the file does not exist, both modes will create it
  • 'x' mode will only create a file if it does not already exist
    • If the file does exist, the 'x' mode will raise a FileExistsError exception
    • useful when you need to ensure that you are not overwriting an existing file
  • For ping command,
    • exit status of 0 means that the ping was successful
    • any other value means that the ping failed
    • result is then written to the log file
  • os.system() function is a simple way to execute shell commands from a Python script
    • has some limitations and potential security issues
    • use the subprocess module for more complex and secure execution of shell command
      • provides more control over how the command is executed and how its output is handled

Closing a File

  • close a file with close() method
file = open('filename.txt', 'r')
# Perform file operations
file.close()
  • why close a file?
    • frees up system resources that were tied up with the file
    • ensures that changes made to the file are saved
      • Some changes made to a file in Python may not be immediately written to disk; closing the file ensures that these changes are not lost
    • prevents further modifications to the file
      • Once a file is closed, attempting to write to it will result in an error

Checking for File Existence

  • can check for file existence with the os.path.exists() function from os module
    • returns True if exists, otherwise False
  • it is good practice to check if a file exists before attempting to perform operations on it
import os
 
# Specify the file path
file_path = 'filename.txt'
 
# Check if the file exists
if os.path.exists(file_path):
    print('The file exists.')
else:
    print('The file does not exist.')

Deleting Files and Folders

Deleting Files

  • can delete a file using the os.remove() function from os module
import os
 
# Specify the file path
file_path = 'filename.txt'
 
# Check if the file exists
if os.path.exists(file_path):
    # Delete the file
    os.remove(file_path)
else:
    print('The file does not exist.')

Deleting a Folder

  • can delete a folder with the os.rmdir() function from the os module
    • can only remove empty directories
  • to remove a directory that is not empty,
    • use the shutil.rmtree() function
      • removes a directory and all its contents
import os
 
# Specify the folder path
folder_path = 'foldername'
 
# Check if the folder exists
if os.path.exists(folder_path):
    # Delete the folder
    os.rmdir(folder_path)
else:
    print('The folder does not exist.')

Comparing Files

The filecmp module in Python is a utility for comparing files and directories.

  • provides functions to compare and provide detailed information about the differences
  • primary uses:
    • searching for duplicate files
    • in comparing directory trees

Example

Example used in network automation:

# Compare two configuration files
if filecmp.cmp('/path/to/config1.txt', '/path/to/config2.txt'):
    print('The configuration files are the same.')
else:
    print('The configuration files are different.')
  • compares two configuration files
    • prints output of result
  • useful for checking if a config file has changed