2012-06-20 30 views
31

Tôi là ứng dụng của tôi, tôi có yêu cầu dưới đây: 1. Có một chuỗi sẽ ghi lại một số nhật ký trong hồ sơ. Tệp nhật ký sẽ được rollovered trong khoảng thời gian nhất định. để giữ các tệp nhật ký nhỏ. 2. Có một luồng khác cũng sẽ thường xuyên xử lý các tệp nhật ký này. ví dụ: Di chuyển các tệp nhật ký sang vị trí khác, phân tích cú pháp nội dung của nhật ký để tạo một số báo cáo nhật ký.Kiểm tra xem tệp có mở hay không (không được sử dụng bởi quy trình khác) trong Python

Nhưng, có một điều kiện là luồng thứ hai không thể xử lý tệp nhật ký đang sử dụng để ghi nhật ký. ở phía mã, các mô phỏng giả như sau:

#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.... 

Vì vậy, làm cách nào để kiểm tra là tệp đã được mở hoặc đang được sử dụng bởi quy trình khác? Tôi đã thực hiện một số nghiên cứu trên internet. Và có một số kết quả:

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

Tôi đã thử mã này, nhưng nó không hoạt động, bất kể tôi sử dụng "r +" hoặc "a +" cờ

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

Mã này có thể làm việc, nhưng nó không thể đạt yêu cầu của tôi, vì tôi không muốn xóa tệp để kiểm tra xem tệp có đang mở hay không.

+0

Bạn đã cố gắng thay đổi 'os.remove' thành' ProcessLogFile' bên trong khối 'try' cuối cùng chưa? Có thể điều chỉnh số lỗi: có 'EBUSY' và [others] (http://docs.python.org/library/errno.html) để thử. –

+1

Bạn có thể muốn đọc câu hỏi này http://stackoverflow.com/questions/2023608/check-what-files-are-open-in-python và đặc biệt là http://stackoverflow.com/a/7142094/546873 câu trả lời – Nicoretti

+0

này Cách thực hiện những điều tương tự trên nền tảng Windows để liệt kê các tệp đang mở. – zengwke

Trả lời

26

Một vấn đề với cố gắng tìm hiểu xem một tập tin đang được sử dụng bởi một quá trình khác là khả năng của một điều kiện chủng tộc. Bạn có thể kiểm tra một tập tin, quyết định rằng nó không được sử dụng, sau đó ngay trước khi bạn mở nó một quá trình (hoặc thread) nhảy vào và lấy nó (hoặc thậm chí xóa nó).

Ok, giả sử bạn quyết định sống với khả năng đó và hy vọng điều đó không xảy ra. Để kiểm tra các tập tin đang được sử dụng bởi các tiến trình khác thì phụ thuộc vào hệ điều hành.

Trên Linux, điều này khá dễ dàng, chỉ cần lặp qua các PID trong/proc. Đây là trình tạo lặp lại trên các tệp được sử dụng cho một PID cụ thể:

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) 

Trên Windows, các API này không được công bố đơn giản. Có một công cụ Sysinternals (handle.exe) có thể được sử dụng, nhưng tôi khuyên bạn nên module PyPi psutil, đó là di động (ví dụ, nó chạy trên Linux là tốt, và có lẽ trên hệ điều hành khác):

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) 
+0

Cảm ơn câu trả lời của bạn. Nhưng, xin lỗi tôi không thể cố gắng cài đặt gói psutil. Kể từ khi giới hạn khung ứng dụng. Tôi không thể bao gồm các gói bên thứ ba khác. Có cách nào có thể làm điều này bằng cách sử dụng python2.4 tinh khiết? – zengwke

+0

Không sử dụng thư viện chuẩn, không. Một cách khác là viết nó vào C hoặc sử dụng ctypes - rất nhiều công việc – cdarke

+1

Rất tốt, nhưng trong ví dụ Linux của bạn, tôi đề nghị sử dụng errno.ENOENT thay vì giá trị 2. – kmarsh

3

Bạn có thể sử dụng inotify để xem hoạt động trong hệ thống tệp. Bạn có thể xem các sự kiện đóng tập tin, cho biết rằng một sự kiện đã xảy ra. Bạn cũng nên thêm điều kiện bổ sung vào kích thước tệp. Đảm bảo bạn lọc ra các sự kiện đóng tập tin từ chuỗi thứ hai.

1

Thay vào đó về việc sử dụng os.remove(), bạn có thể sử dụng các workaround sau đây trên 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 
+3

Điều kiện chủng tộc ở đây. Nếu người dùng ngắt chương trình (ctrl-c) sau lần đổi tên đầu tiên thì tên tệp sẽ không được khôi phục và người dùng sẽ không biết điều kiện này. Ở mức tối thiểu bạn nên ghép nối hai thao tác đổi tên lại với nhau. Các bản in nên đi sau. Điều này giảm thiểu cửa sổ nguy hiểm. os.rename (---); os.rename (---); print "Access ---" Bạn cũng nên bắt ngoại lệ KeyboardInterrupt và SystemExit để có thể khôi phục tên tệp trước khi thoát ứng dụng. –

+1

hoặc chỉ sử dụng cuối cùng – user25064

+0

Đây là một giải pháp rất ngu ngốc! các tập tin thực thi và dll có thể được đổi tên trong Windows khi mở ... –

14

Tôi thích câu trả lời của Daniel, nhưng tôi nhận ra rằng nó an toàn hơn và đơn giản hơn để đổi tên các tập tin với tên nó đã có. Điều đó giải quyết các vấn đề được đưa ra trong các coments để trả lời của mình. Tôi sẽ chỉ nói điều này trong một bình luận, nhưng tôi không có điểm.Dưới đây là các mã:

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) 
+1

Tôi khá chắc chắn điều này sẽ không hoạt động trên hệ điều hành không phải của Windows (hệ thống Linux của tôi sẵn sàng cho phép tôi đổi tên một tệp cơ sở dữ liệu mà tôi đã mở trong một quy trình khác). –

6

Bạn có thể kiểm tra xem một tập tin có một ngày xử lý nó bằng cách sử dụng chức năng tiếp theo (nhớ để vượt qua đường dẫn đầy đủ đến tập tin đó):

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 
+0

Thật tuyệt! Cảm ơn – ZHAJOR

0

Tôi biết tôi đến cuối buổi tiệc nhưng tôi cũng có vấn đề này và tôi đã sử dụng lệnh lsof để giải quyết nó (điều mà tôi nghĩ là mới từ các phương pháp được đề cập ở trên). Với lsof, về cơ bản chúng tôi có thể kiểm tra các quy trình đang sử dụng tệp cụ thể này. Đây là cách tôi đã thực hiện:

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 

chỉ viết mã xử lý nhật ký của bạn trong phần ngoại trừ và bạn sẵn sàng sử dụng.

Các vấn đề liên quan