View on GitHub

pycdlib

Python library to read and write ISOs

Example: Opening an existing ISO

This example will show how to examine an existing ISO. Here’s the complete code for this example:

import sys
import pycdlib

iso = pycdlib.PyCdlib()
iso.open(sys.argv[1])

for child in iso.list_children(iso_path='/'):
    print(child.file_identifier())

iso.close()

Let’s take a closer look at the code.

import sys
import pycdlib

As we’ve seen before, import pycdlib. We also import the sys module so we get access to the command-line arguments.

iso = pycdlib.PyCdlib()
iso.open(sys.argv[1])

As we saw in the last example, create a new PyCdlib object. Once we have the object, we can then open up the file passed on the command-line. During the open, PyCdlib will parse all of the metadata on the ISO, so if the file is coming over a network, this may take a bit of time. Note that besides the open method, there is also an open_fp method that takes an arbitrary file-like object.

for child in iso.list_children(iso_path='/'):
    print(child.file_identifier())

Use the list_children API from PyCdlib to iterate over all of the files and directories at the root of the ISO. As discussed in the Creating a new, basic ISO example, the paths are Unix-like absolute paths.

Note that iso_path selects the plain ISO9660 view of the filesystem, so the names printed above will be the ISO9660 names. Those are restricted to upper-case letters, digits, and underscores, are truncated to 8.3 (or 31 characters, depending on the interchange level), and carry a trailing version number, so a file that shows up as install-tl-windows.bat on a desktop operating system may be listed here as INSTALL_.BAT;1. The full names live in one of the ISO extensions: Rock Ridge (mostly Linux/Unix ISOs), Joliet (mostly Windows ISOs), or UDF (DVDs and many modern ISOs). Most real-world ISOs carry at least one of these, and desktop operating systems prefer them over the ISO9660 names. To see the same names that a desktop would show, check which extensions the ISO has with has_rock_ridge, has_joliet, and has_udf, and then pass rr_path, joliet_path, or udf_path instead of iso_path:

if iso.has_udf():
    kwargs = {'udf_path': '/'}
elif iso.has_rock_ridge():
    kwargs = {'rr_path': '/'}
elif iso.has_joliet():
    kwargs = {'joliet_path': '/'}
else:
    kwargs = {'iso_path': '/'}

for child in iso.list_children(**kwargs):
    if child.is_dot() or child.is_dotdot():
        continue
    print(iso.full_path_from_dirrecord(child, rockridge='rr_path' in kwargs))

The same iso_path/rr_path/joliet_path/udf_path choice applies to every API that takes a path, including get_record, walk, get_file_from_iso, and open_file_from_iso. Note that the path must be spelled in the namespace you select; a Joliet path uses the Joliet name (/install-tl-windows.bat), not the ISO9660 name (/INSTALL_.BAT;1). full_path_from_dirrecord is used above because it decodes the name in whichever encoding the selected namespace uses (Joliet names, for instance, are UCS-2), while file_identifier returns the raw on-disk bytes.

iso.close()

Close out the PyCdlib object, releasing all resources and invalidating the contents. After this call, the object can be reused to create a new ISO or open up an existing ISO.


<-- Example: Creating a new, basic ISO
Top
Example: Extracting data from an existing ISO -->