Подтвердить что ты не робот

Проверьте, не открыт ли файл (не используется другим процессом) в Python

В моем приложении у меня есть следующие запросы: 1. Существует один поток, который будет регулярно записывать некоторые журналы в файл. Файл журнала будет опрокинут в определенном интервале. для хранения файлов журнала. 2. Существует и другой поток, который будет регулярно обрабатывать эти файлы журналов. ex: переместите файлы журнала в другое место, проанализируйте содержимое журнала, чтобы сгенерировать несколько отчетов журнала.

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

#code in second thread to process the log files
for logFile in os.listdir(logFolder):
     if not file_is_open(logFile) or file_is_use(logFile):
          ProcessLogFile(logFile) # move log file to other place, and generate log report....

Итак, как я могу проверить, что файл уже открыт или используется другим процессом? Я провел некоторое исследование в Интернете. И есть некоторые результаты:

try:
   myfile = open(filename, "r+") # or "a+", whatever you need
except IOError:
    print "Could not open file! Please close Excel!"

Я пробовал этот код, но он не работает, независимо от того, я использую флаг "r +" или "a +"

try:
   os.remove(filename) # try to remove it directly
except OSError as e:
    if e.errno == errno.ENOENT: # file doesn't exist
        break

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

4b9b3361

Ответ 1

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

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

В Linux это довольно просто, просто перебирайте PID в /proc. Вот генератор, который выполняет итерацию над файлами, используемыми для определенного PID:

def iterate_fds(pid):
    dir = '/proc/'+str(pid)+'/fd'
    if not os.access(dir,os.R_OK|os.X_OK): return

    for fds in os.listdir(dir):
        for fd in fds:
            full_name = os.path.join(dir, fd)
            try:
                file = os.readlink(full_name)
                if file == '/dev/null' or \
                  re.match(r'pipe:\[\d+\]',file) or \
                  re.match(r'socket:\[\d+\]',file):
                    file = None
            except OSError as err:
                if err.errno == 2:     
                    file = None
                else:
                    raise(err)

            yield (fd,file)

В Windows это не так просто, API не публикуются. Существует инструмент sysinternals (handle.exe), который можно использовать, но я рекомендую модуль PyPi psutil, который является переносимым (то есть он работает и в Linux, и, возможно, на другой ОС):

import psutil

for proc in psutil.process_iter():
    try:
        flist = proc.get_open_files()
        if flist:
            print(proc.pid,proc.name)
            for nt in flist:
                print("\t",nt.path)

    # This catches a race condition where a process ends
    # before we can examine its files    
    except psutil.NoSuchProcess as err:
        print("****",err) 

Ответ 2

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

import os

f = 'C:/test.xlsx'
if os.path.exists(f):
    try:
        os.rename(f, f)
        print 'Access on file "' + f +'" is available!'
    except OSError as e:
        print 'Access-error on file "' + f + '"! \n' + str(e)

Ответ 3

Вы можете проверить, имеет ли файл дескриптор на нем, используя следующую функцию (не забудьте передать полный путь к этому файлу):

import psutil

def has_handle(fpath):
    for proc in psutil.process_iter():
        try:
            for item in proc.open_files():
                if fpath == item.path:
                    return True
        except Exception:
            pass

    return False

Ответ 4

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

Ответ 5

Вместо использования os.remove() вы можете использовать следующее обходное решение для Windows:

import os

file = "D:\\temp\\test.pdf"
if os.path.exists(file):
    try:
        os.rename(file,file+"_")
        print "Access on file \"" + str(file) +"\" is available!"
        os.rename(file+"_",file)
    except OSError as e:
        message = "Access-error on file \"" + str(file) + "\"!!! \n" + str(e)
        print message

Ответ 6

Я знаю, что опаздываю на вечеринку, но у меня также была эта проблема, и я использовал команду lsof для ее решения ( который, я думаю, новеньен с подходами, упомянутыми выше). С lsof мы можем в основном проверить процессы, которые используют этот конкретный файл. Вот как я это сделал:

from subprocess import check_output,Popen, PIPE
try:
   lsout=Popen(['lsof',filename],stdout=PIPE, shell=False)
   check_output(["grep",filename], stdin=lsout.stdout, shell=False)
except:
   #check_output will throw an exception here if it won't find any process using that file

просто напишите свой код обработки журнала в другой части, и вы хорошо пойдете.