Yoda
Yoda

Reputation: 690

Good way to determine the correct filename from a small set of possible filenames in Python

I have a python project for a GUI to be used with the slurm queuing manager at our computing cluster. One thing I can do is to print the contents of certain files for a specific job in a text window.

However, the extensions people use for the same type of file will sometimes change. I could program it such that it works for me, but I also want to be able to look up other people's files.

The way I have solved this is the following

extensions = [".ex1", ".ext2", "ext3"]
for ext in extensions:
    try:
        f = open(jobname+ext), "r")
        content = f.read()
        f.close()

        <doing some stuff with content>

    except IOError:
        if ext == extensions[-1]:
            print("File not found")
            return

If the actual extension used is covered by extensions, then my code will find it. I would like to know if more experienced programmers have a better/more elegant/more efficient way of doing it. Luckily the files to be read are very small, so looping over all the possibilities will not take much time. But this particular solution might not be suitable for other cases.

Upvotes: 1

Views: 75

Answers (4)

dudenr33
dudenr33

Reputation: 1169

As I understand the Question, you already know the filename and path, and only the extension is unknown. Use the glob package to find all files with that name like this:

from glob import glob

matches = glob("/path/to/files/knownfilename.*")
if not matches:
    print("File not found!")
    return
try:
    with open(matches[0], "r") as f:
        content = f.read()
    # do stuff
except IOError:
    print("Error reading file {}".format(matches[0]))

In this case you might have to deal with the possibility that

  • there are multiple files with that name and different extensions
  • the first file in the matches list is not the kind of file you want (maybe some backup file with .bak extension or whatever), so you might also want to blacklist some extensions

Upvotes: 1

Christoph Burschka
Christoph Burschka

Reputation: 4689

Even if that works, the logic of comparing the current extension with the end of the list feels weird. In the worst case, if the last extension is accidentally duplicated earlier in the list, this would lead to hard-to-diagnose errors.

Since (presumably) you already return out of the loop as soon as you have found the file, you could just put the "missing-file" behavior after the loop (where it will only be reached if no file was found), and leave the catch-block empty:

extensions = [".ex1", ".ext2", ".ext3"]
for ext in extensions:
    try:
        with open(jobname+ext), "r") as f:
            content = f.read()

            <doing some stuff with content>

            return

    except IOError:
        pass

print("File not found")

Upvotes: 0

blhsing
blhsing

Reputation: 106455

You can use os.listdir('.') to get a list of file names in the current working directory, iterate through the list with a for loop, and slice the file name from the length of jobname and use the in operator to test if it is one of extension names in the extensions list/tuple. break after processing the file when a file is found with the desired name. Use the else block for the for loop to print a File not found message if the loop finishes without breaking:

import os
extensions = '.ext1', '.ext2', '.ext3'
for filename in os.listdir('.'):
    if filename.startswith(jobname) and filename[len(jobname):] in extensions:
        with open(filename) as f:
            content = f.read()
            # doing some stuff with content
        break
else:
    print("File not found")

Upvotes: 0

Eugene Yarmash
Eugene Yarmash

Reputation: 149736

You could use the with statement to open a file and then have it automatically closed. Also, you could omit the mode parameter to open() (which defaults to 'r') and probably add a break after you found a valid extension:

extensions = [".ex1", ".ext2", "ext3"]
for ext in extensions:
    try:
        with open(jobname+ext)) as f:
            content = f.read()            

        # do some stuff with content
        break    
    except IOError:
        if ext == extensions[-1]:
            print("File not found")
            return

Upvotes: 0

Related Questions