Python повторит попытку открыть файл

Как лучше всего попытаться открыть файл и повторить попытку через n секунд?

В настоящее время я делаю:

import os
from os import path
import shutil

dir_path = path.abspath(path.join("foo", "bar"))
destination_path = path.abspath(path.join("foo", "dest_dir"))

for f in dir_path:
    try:
        # try to open the file if the file isn't used any longer
        file_opened = open(f, 'r')
        # move the file on successful opening
        shutil.move(file_opened, destination_path)
        file_opened.close()
    except IOError:
        return False

Итак, на данный момент я не обрабатываю исключение. Я думаю о создании дополнительной функции для открытия файла и вызова функции для исключения с помощью time.sleep(n)

Однако я уверен, что должно быть что-то еще...

я не использую

with open(f, 'rb') as file_opened: 
    do whatever` 

РЕДАКТИРОВАТЬ:

Один процесс создает файл, и я хочу, чтобы процесс Python переместил файл, как только я буду уверен, что запись/создание файла завершено. Итак, я добавил Shutil.move в приведенный выше код, чтобы показать всю ситуацию.

РЕДАКТИРОВАТЬ:

Пожалуйста, найдите ниже код, который я разработал для решения проблемы. Я закончил тем, что написал собственное решение для его обработки:

import os
from os import path
import psutil
from retry import retry
import shutil
from subprocess import check_output,Popen, PIPE
import glob
import time


class FileHandler:
    def __init__(self, fn_source, dir_source):
        self.file_source_name = fn_source
        self.file_source_path = path.join(dir_source, self.file_source_name)
        self.dir_dest_path = path.join(dir_source, "test")
        self.file_dest_path = path.join(self.dir_dest_path, self.file_source_name)

    def check_file(self):
        if os.path.exists(self.file_source_path):
            try:
                os.rename(self.file_source_path, self.file_source_path)
                print("file renamed")
                return True
            except:
                print("can not rename the file..retrying")
                time.sleep(1)
                self.check_file()
        else:
            print("source file does not exist...retrying")
            time.sleep(5)
            self.check_file()

    def check_destination(self):
        if os.path.exists(self.file_source_path) and not os.path.exists(self.file_dest_path):
            return True
        elif os.path.exists(self.file_source_path) and os.path.exists(self.file_dest_path):
            try:
                print(self.file_dest_path, self.file_source_name)
                os.remove(self.file_dest_path)
                return True
            except Exception as e:
                print("can not remove the file..retrying")
                time.sleep(5)
                self.check_destination()

    def move_file(self):
        if self.check_destination():
            print(self.file_source_path)
            shutil.move(self.file_source_path, self.file_dest_path)
            print("moved", str(self.file_source_path))
            return True
        else:
            print("can not move the file..retrying")
            time.sleep(1)
            self.move_file()

    def file_ops(self):
        if self.check_file():
            self.move_file()
        else:
            print("source does not exist")
            time.sleep(1)
            self.file_ops()
        return True


def each_file_ops(fn, dir_source):
    fh = FileHandler(fn, dir_source)
    return fh.file_ops()


def main(dir_source):
    dir_files = glob.glob(path.join(dir_source, '*.txt'))
    if dir_files:
        [each_file_ops(f, dir_source) for f in dir_files]
    else:
        print("source dir is empty")
        time.sleep(1)
        main(dir_source)


if __name__ == '__main__':
    main(path.join(""))

person mothership    schedule 21.06.2018    source источник
comment
Какой смысл пытаться открыть файл, который не удалось открыть?   -  person DYZ    schedule 21.06.2018
comment
Дело в том, что если вы не можете открыть файл прямо здесь и сейчас, потому что он может быть все еще используется, вы можете вернуться и снова проверить, можете ли вы открыть файл?   -  person mothership    schedule 21.06.2018
comment
например monster1 создает файл для вас, но нет возможности поговорить с monster1, поэтому вместо этого вы можете перепроверить, чтобы попытаться открыть файл и посмотреть, ушел ли monster1, а файл остался для вас, чтобы вы могли поиграть с ним.   -  person mothership    schedule 21.06.2018
comment
Вам следует подождать, пока блокировка станет доступной, а не продолжать попытки.   -  person DYZ    schedule 21.06.2018
comment
Что такое file_path? Когда вы используете переменную цикла f?   -  person schwobaseggl    schedule 21.06.2018
comment
какой замок? Я не многопоточен, если вы имеете в виду это (GIL?), но я могу вас неправильно понять.   -  person mothership    schedule 21.06.2018
comment
Привет швобасеггль. Виноват. Это должно быть ф. Извиняюсь. Я только что исправил это. Я переписывал код с экрана, а не копировал.   -  person mothership    schedule 21.06.2018
comment
Какой ОС вы пользуетесь в первую очередь? Единственный способ получить файл в Linux — это заблокировать его. Windows, вероятно, использует аналогичный механизм.   -  person DYZ    schedule 21.06.2018
comment
Поскольку вы открываете файл в режиме чтения, не должно быть никаких исключений, кроме file not available (если файл на самом деле недоступен). Для файла можно установить несколько блокировок чтения. Проблема может возникнуть, если вы пытаетесь открыть файл в режиме добавления или записи, в этом случае вам придется подождать, пока предыдущий пользователь не снимет блокировку (при условии, что файл уже открыт в режиме записи/добавления).   -  person Umesh Kaushik    schedule 21.06.2018
comment
Я пытаюсь сделать: Shutil.move(f, destination_dir) и это то, что вызывает исключение. Итак, в основном, я хочу переместить файл, как только я уверен, что файл больше не используется.   -  person mothership    schedule 21.06.2018


Ответы (2)


Вы можете использовать модуль retry для таких повторных попыток. Это делает код более чистым. pip install retry следует установить модуль

from retry import retry
import shutil

@retry((FileNotFoundError, IOError), delay=1, backoff=2, max_delay=10, tries=100)
def attempt_to_move_file(fname, dest_path):
    # Your attempt to move file
    # shutil.move(fname, destination_path)

С приведенным выше кодом, когда вызывается attempt_to_move_file, он будет повторяться (максимум до 100 попыток) всякий раз, когда мы нажимаем FileNotFoundError или IOError, и повторная попытка происходит со сном 1, 2, 4, 8, 10, 10, 10... секунд между попытками

person Sunitha    schedule 21.06.2018
comment
Shutil.move() по-прежнему будет перемещать файл независимо от того, открыт файл или нет, однако, если в файле выполняется какая-либо операция записи, она все равно будет продолжать выполняться в файле в новом местоположении. - person Umesh Kaushik; 21.06.2018
comment
нет, Shutil.move() не будет перемещать файл, если файл используется другим процессом. - person mothership; 21.06.2018
comment
@mothership, пожалуйста, прокомментируйте, что я сделал под своим ответом. - person Umesh Kaushik; 21.06.2018
comment
Просто для протокола, как указал @UmeshKaushik, использование shutil.move() не будет лучшим решением, поскольку оно может перемещать частично созданные файлы. По крайней мере, такое поведение я увижу на машинах Linux. Как указывали некоторые другие, лучшее решение - заставить другой процесс, создающий файл, создать и получить блокировку этого файла до тех пор, пока он не завершит запись. Затем вы должны подождать, пока эта блокировка не будет выпущена в вашем коде. - person Sunitha; 21.06.2018
comment
@Sunitha ... Я не могу влиять на автора, поэтому я не могу заставить его установить блокировку и т. Д., Поэтому мой подход к этому с точки зрения читателя. - person mothership; 21.06.2018
comment
@Umesh Kaushik ... пожалуйста, загрузите код в github/bitbucket и т. д. вместо google.drive, так как я не могу читать google.drive - person mothership; 21.06.2018
comment
@mothership это видео, и оно общедоступно drive.google.com/open?id=1zsWxVOGS5_lmcUW9CGA9Z96ZYLPlR1Le . и чтобы решить вашу проблему, проверьте этот stackoverflow.com/questions/11114492/ , здесь вы можете отфильтровать, если процесс использует файл или нет. - person Umesh Kaushik; 21.06.2018

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

import shutil

file_name = 'trytry.csv'

shutil.copyfile(file_name, '/Users/umeshkaushik/PycharmProjects/newtry.csv')
shutil.move(file_name, '/Users/umeshkaushik/PycharmProjects/newtry1.csv')

Код выше работает нормально. Просто убедитесь, что вы указываете правильный путь ввода и вывода.

person Umesh Kaushik    schedule 21.06.2018
comment
Если процесс A создает файл и записывает в него строки, то как вы проверяете с помощью приведенного выше кода, если процесс A все еще не записывает в файл, так как вы проверяете, не открыт ли файл или как вы проверяете, что файл не используется и написание завершено? Приведенный выше код сделает снимок файла в определенный момент времени, в то время как на самом деле запись может быть завершена через несколько секунд после того, как вы сделаете снимок. - person mothership; 21.06.2018
comment
поэтому я пытаюсь открыть файл, а затем закрыть его, а затем переместить. - person mothership; 21.06.2018
comment
Ваши утверждения в вашем коде неверны. Я не создаю файл. Другой процесс создает файл. Я просто открываю его в режиме чтения, чтобы посмотреть, смогу ли я его открыть. Я закрываю его сразу после открытия, а затем перемещаю, как только я уверен, что могу открыть и закрыть его, чтобы он сказал мне, что файл не используется. - person mothership; 21.06.2018
comment
Согласен, ошибся, написав в ответе! Удаление этой части. - person Umesh Kaushik; 21.06.2018
comment
А для записей возможны множественные блокировки записи в файле. - person Umesh Kaushik; 21.06.2018
comment
что это мне говорит? Как избежать множественных блокировок записи, если процесс1 (Scala) создает текстовый файл, а процесс1 (Python) выбирает файл только в том случае, если запись файла завершена? - person mothership; 21.06.2018
comment
Я не уверен насчет scala, сценарий, который я упомянул, написан на python. 1. возможны множественные блокировки записи, и все они будут записываться в файл. 2. Shutil.move переместит файл независимо от блокировок, но также продолжит запись в новое место. Однако, если вы хотите применить жесткое условие, что файл не должен перемещаться, если он используется каким-либо процессом, я думаю, это может вам помочь stackoverflow.com /вопросы/11114492/ - person Umesh Kaushik; 21.06.2018
comment
почему вы ссылаетесь на множественные блокировки, если я не использую многопоточность или многопроцессорность с Python. Я этого не говорил. Я запускаю один процесс с Python, пытаясь переместить файл, если он не используется другим процессом, который создает файл. Другой процесс может быть, например. Scala, Java, Cobol или что-то еще. - person mothership; 21.06.2018
comment
Shutil.move() не будет перемещать файл, если файл используется другим процессом. - person mothership; 21.06.2018
comment
сделал это только для того, чтобы показать вам: дайте мне знать, если у вас возникнут какие-либо проблемы при просмотре этого: drive.google.com/file/d/1zsWxVOGS5_lmcUW9CGA9Z96ZYLPlR1Le/ Это показывает, что Shutil переместит файл. - person Umesh Kaushik; 21.06.2018
comment
и я имел в виду несколько замков, чтобы охватить все сценарии. - person Umesh Kaushik; 21.06.2018