Хороший способ определить правильное имя файла из небольшого набора возможных имен файлов в Python

#python

#python

Вопрос:

У меня есть проект Python для графического интерфейса, который будет использоваться с менеджером очередей slurm в нашем вычислительном кластере. Единственное, что я могу сделать, это распечатать содержимое определенных файлов для конкретного задания в текстовом окне.

Однако расширения, которые люди используют для файлов одного и того же типа, иногда меняются. Я мог бы запрограммировать его так, чтобы он работал для меня, но я также хочу иметь возможность просматривать файлы других людей.

Способ, которым я решил это, заключается в следующем

 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
  

Если фактическое используемое расширение покрыто extensions , то мой код найдет его. Я хотел бы знать, есть ли у более опытных программистов лучший / более элегантный / более эффективный способ сделать это. К счастью, файлы для чтения очень маленькие, поэтому перебор всех возможностей не займет много времени. Но это конкретное решение может не подойти для других случаев.

Комментарии:

1. Вы могли бы рассмотреть возможность удаления и публикации в Code Review. SE , поскольку Stack Overflow больше подходит для кода, который не работает, в отличие от вопросов о лучших практиках и оптимизации рабочего кода.

2. Почему пользователи не могут вводить расширения файлов вместе с именем файла? В качестве альтернативы, вы могли бы использовать glob пакет, чтобы найти все файлы с этим именем (независимо от расширения, например somefilename.*) и попытаться прочитать файл, если он был найден.

Ответ №1:

Насколько я понимаю вопрос, вы уже знаете имя файла и путь, и неизвестно только расширение. Используйте glob пакет, чтобы найти все файлы с таким именем следующим образом:

 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]))
  

В этом случае вам, возможно, придется иметь дело с возможностью того, что

  • существует несколько файлов с таким именем и разными расширениями
  • первый файл в matches списке — это не тот файл, который вам нужен (возможно, какой-то файл резервной копии с расширением .bak или что-то еще), поэтому вы также можете захотеть внести в черный список некоторые расширения

Ответ №2:

Вы могли бы использовать with инструкцию, чтобы открыть файл, а затем автоматически закрыть его. Кроме того, вы могли бы опустить параметр mode на open() (который по умолчанию равен 'r' ) и, вероятно, добавить break после того, как вы нашли допустимое расширение:

 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
  

Комментарии:

1. Хотя оба пункта верны, основная проблема не решена. Функция по-прежнему будет находить только файлы с предопределенными расширениями.

Ответ №3:

Вы можете использовать os.listdir('.') , чтобы получить список имен файлов в текущем рабочем каталоге, выполнить итерацию по списку с помощью for цикла и вырезать имя файла из длины jobname и использовать in оператор, чтобы проверить, является ли это одним из имен расширений в extensions списке / кортеже. break после обработки файла, когда найден файл с нужным именем. Используйте else блок для for цикла, чтобы напечатать File not found сообщение, если цикл завершается без прерывания:

 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")
  

Комментарии:

1. Обратите внимание, что это перебирает каждый файл в каталоге, а не проверяет, существует ли один из нескольких возможных файлов. Это будет намного медленнее в каталогах с большим количеством файлов.

Ответ №4:

Даже если это сработает, логика сравнения текущего расширения с концом списка кажется странной. В худшем случае, если последнее расширение случайно дублируется ранее в списке, это приведет к труднодиагностируемым ошибкам.

Поскольку (предположительно) вы уже выходите из цикла, как только находите файл, вы могли бы просто указать поведение «missing-file» после цикла (где оно будет достигнуто, только если файл не был найден), и оставить блок catch пустым:

 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")