我是我的申请,我有以下要求: 1.有一个线程会定期记录一些日志文件。日志文件将在特定时间间隔内进行翻转。用于保持日志文件较小。 2.还有另一个线程也会定期处理这些日志文件。例如:将日志文件移动到其他位置,解析日志的内容以生成一些日志报告。
但是,有一个条件是第二个线程无法处理用于记录日志的日志文件。在代码方面,伪代码类似如下:
#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
此代码可以使用,但无法达到我的请求,因为我不想删除该文件以检查它是否已打开。
答案 0 :(得分:35)
试图查明某个文件是否被其他进程使用的问题是竞争条件的可能性。您可以检查一个文件,确定它没有被使用,然后在打开它之前,另一个进程(或线程)跳进并抓取它(甚至删除它)。
好吧,让我们说你决定忍受这种可能性并希望它不会发生。检查其他进程使用的文件是依赖于操作系统的。
在Linux上它很容易,只需遍历/ proc中的PID。这是一个生成器,它迭代用于特定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上运行,也可能在其他操作系统上运行):< / p>
import psutil
for proc in psutil.process_iter():
try:
# this returns the list of opened files by the current process
flist = proc.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)
答案 1 :(得分:17)
我喜欢Daniel的回答,但我意识到将文件重命名为已有的名称会更安全,更简单。这解决了他在答案中提出的问题。我会在评论中说这个,但我没有分数。这是代码:
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)
答案 2 :(得分:15)
您可以使用下一个函数检查文件是否有句柄(请记住传递该文件的完整路径):
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
答案 3 :(得分:3)
您可以使用 inotify 来监视文件系统中的活动。您可以监视文件关闭事件,指示已发生翻转。您还应该在文件大小上添加其他条件。确保从第二个线程中过滤掉文件关闭事件。
答案 4 :(得分:3)
我知道我迟到了,但我也遇到了这个问题,我使用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
只需在except部分写下你的日志处理代码,你就可以了。
答案 5 :(得分:2)
而不是使用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 :(得分:0)
稍微改进的 one of the answers from above 版本。
from pathlib import Path
def is_file_in_use(file_path):
path = Path(file_path)
if not path.exists():
raise FileNotFoundError
try:
path.rename(path)
except PermissionError:
return True
else:
return False