Как создать именованный временный файл в Windows на Python? - PullRequest
10 голосов
/ 31 марта 2010

У меня есть программа на Python, которая должна создать именованный временный файл, который будет открываться и закрываться пару раз в течение программы и должен быть удален при выходе из программы. К сожалению, ни один из параметров в tempfile не работает:

  • TemporaryFile не имеет видимого имени
  • NamedTemporaryFile создает объект в виде файла. Мне просто нужно имя файла. Я пытался закрыть объект, который он возвращает (после установки delete = False), но при попытке открыть файл позже я получаю потоковые ошибки.
  • SpooledTemporaryFile не имеет видимого имени
  • mkstemp возвращает как открытый объект файла, так и имя; он не гарантирует удаления файла при выходе из программы
  • mktemp возвращает имя файла, но не гарантирует удаление файла при выходе из программы

Я пытался использовать mktemp 1 в менеджере контекста, например так:

def get_temp_file(suffix):
    class TempFile(object):
        def __init__(self):
            self.name = tempfile.mktemp(suffix = '.test')

        def __enter__(self):
            return self

        def __exit__(self, ex_type, ex_value, ex_tb):
            if os.path.exists(self.name):
                try:
                    os.remove(self.name)
                except:
                    print sys.exc_info()

     return TempFile()

... но это дает мне WindowsError(32, 'The process cannot access the file because it is being used by another process'). Имя файла используется процессом, который порождает моя программа, и, хотя я и завершаю, что процесс завершается перед выходом из системы, кажется, что состояние гонки вне моего контроля.

Какой лучший способ справиться с этим?

1 Мне не нужно беспокоиться о безопасности здесь; это часть модуля тестирования, поэтому самое страшное, что может сделать нечестивый, это заставить наши модульные тесты внезапно провалиться. Ужас!

Ответы [ 3 ]

4 голосов
/ 24 марта 2011

Мне нужно было что-то похожее на это сегодня, и в итоге я написал свой собственный. Я использую atexit.register () для регистрации функции обратного вызова, которая удаляет файл при выходе из программы.

Обратите внимание, что стандарты кодирования для этого немного отличаются от типичных стандартов кодирования Python (camelCase, а не using_underscores). Настроить по желанию, конечно.

def temporaryFilename(prefix=None, suffix='tmp', dir=None, text=False, removeOnExit=True):
    """Returns a temporary filename that, like mkstemp(3), will be secure in
    its creation.  The file will be closed immediately after it's created, so
    you are expected to open it afterwards to do what you wish.  The file
    will be removed on exit unless you pass removeOnExit=False.  (You'd think
    that amongst the myriad of methods in the tempfile module, there'd be
    something like this, right?  Nope.)"""

    if prefix is None:
        prefix = "%s_%d_" % (os.path.basename(sys.argv[0]), os.getpid())

    (fileHandle, path) = tempfile.mkstemp(prefix=prefix, suffix=suffix, dir=dir, text=text)
    os.close(fileHandle)

    def removeFile(path):
        os.remove(path)
        logging.debug('temporaryFilename: rm -f %s' % path)

    if removeOnExit:
        atexit.register(removeFile, path)

    return path

Суперосновный тестовый код:

path = temporaryFilename(suffix='.log')
print path
writeFileObject = open(path, 'w')
print >> writeFileObject, 'yay!'
writeFileObject.close()

readFileObject = open(path, 'r')
print readFileObject.readlines()
readFileObject.close()
2 голосов
/ 02 апреля 2010

У меня была точно такая же проблема, когда мне нужно было сохранить загруженный файл в открытый временный файл с помощью модуля csv. Самым раздражающим было то, что имя файла в WindowsError указывало на временный файл, но сохранение загружаемого содержимого файла в буфер StringIO и помещение данных буфера во временный файл устранило проблему. Для моих нужд этого было достаточно, так как загруженные файлы всегда помещаются в памяти.

Проблема была только тогда, когда я загрузил файл со скриптом через CGI Apache, когда я запустил аналогичный скрипт из консоли, но я не смог воспроизвести проблему.

1 голос
/ 31 марта 2010

Если вас не волнует безопасность, что с этим не так?

tmpfile_name = tempfile.mktemp()
# do stuff
os.unlink(tmpfile_name)

Возможно, вы пытаетесь чрезмерно спроектировать это. Если вы хотите убедиться, что этот файл всегда удаляется при выходе из программы, вы можете заключить ваше выполнение main() в try/finally. Сохраняйте это простым!

if __name__ == '__main__':
    try:
        tmpfile_name = tempfile.mktemp()
        main()
    except Whatever:
        # handle uncaught exception from main()
    finally:
        # remove temp file before exiting
        os.unlink(tmpfile_name)
...