Pythonでファイルのロック@Windows|Linux
ファイルのロックがね。WindowsとLinuxと違うわけですが。
基本的にはPythonではOSの違いなんかはほぼ考慮しないで大丈夫な感じなわけですが、
ファイルの排他ロックなんかだけは、共通に書けないのは、まぁしかたないことです。
ということで、マスタ的にjsonファイルを扱ったりして、PHPでもC++でもPythonでもアクセスするような感じにするので、やっぱり、ファイルのロックとかはどうしても必要になります。
しかし、なんだりかんだりで、Python@Windowsの場合のファイルロックが、なんかマニュアル見てもよくわかんなかったりしたので、それを検証してみましょう。
Windowsの場合のファイルロックはどうやるの?
LINUXとかの場合には、
fcntl.flock(f, fcntl.LOCK_EX | fcntl.LOCK_NB)
とか書けばよいのですが、Windowsの場合には、どうするかっていうと、こんな風にかくようです。
msvcrt.locking(fh.fileno(), msvcrt.LK_NBLCK, 500000000)
ファイルをOpenするモード
実は、これにちょっと戸惑ってしまいまして。
要するに、WindowsのようにファイルのOpenモードと、ロックするモードを同時に指定できないため、わずかな時間差を考慮し始めるとメンドイと思ったわけです。
ということで、いろいろやってみた結果、
rb+しかない
という結論です。要するに、
seekしてからwriteするには、これ以外は思ったようにいかなかったからなのです。
まあwriteモードは、最初に切り詰めちゃいますからそうなんですが、
ab+とかやっても、先頭にseekしてからwriteしても、末尾に追加されてしまう
という結果だったということです。
よって、基本、rb+でOpenすることを基本にしたクラスを作ってしまいます。
そして、lockするところで例外を拾って排他処理をかけましょ。
あと、、すみません。テキストモードとか使ったことないのです。
どこで使うかほぼ意味がわかりませんし。。
しかし、、、lockingの時のサイズがよくわからんなぁーー^^;
作ってみた、第一弾
import os
import msvcrt
#-----------------------------------------
if os.name != 'nt':
import fcntl
#-----------------------------------------
class hiraFile:
#---------------------------------------
def __init__(self):
self.f = None
self.fname = ""
self.mode = ""
self.maxloop = 50
self.locksize = 1024
#---------------------------------------
def __enter__(self):
#print("前処理")
return self
#--------------------------
def __exit__(self, exc_type, exc_value, traceback):
#print("後処理")
a = 0
#--------------------------
def __del__(self):
if self.f != None:
self.f.close()
self.f = None
self.fname = ""
#--------------------------
def isLinux(self):
return os.name != 'nt'
def isWindows(self):
return os.name == 'nt'
#--------------------------
# open mode:r,w,aで受け付ける
#--------------------------
def open(self,fname,mode="r"):
try:
self.f = open(fname,"rb+")
try:
if(mode != "r"):
if(self.isWindows()):
msvcrt.locking(self.f.fileno(), msvcrt.LK_NBLCK, self.locksize)
else:
fcntl.flock(self.f, fcntl.LOCK_EX | fcntl.LOCK_NB)
if(mode == "a"):
self.f.seek(0,2) #LAST
else:
self.f.seek(0) #TOP
return True
except Exception as e:
self.f.close()
self.f = None
except Exception as e:
self.f = None
return False
#--------------------------
def close(self):
if self.f:
if(self.isWindows()):
msvcrt.locking(self.f.fileno(), msvcrt.LK_UNLCK, self.locksize)
else:
fcntl.flock(self.f, fcntl.LOCK_UN)
self.f.close()
self.f = None
#---------------------------------------
def write(self,dat,n=0):
try:
if(n == 0):
v = self.f.write(dat.encode("utf-8"))
else:
v = self.f.write(dat,n)
except Exception as e:
v = False
return v
#--------------------------
def read(self,n=0):
try:
if(n == 0):
v = self.f.read()
else:
v = self.f.read(n)
except Exception as e:
v = False
return v
#--------------------------
def seek(self,a,b):
try:
v = self.f.seek(a,b)
except Exception as e:
v = False
return v
#--------------------------
def truncate(self,a):
try:
v = self.f.truncate(a)
except Exception as e:
v = False
return v
#--------------------------
def getPos(self):
try:
v = self.f.tell()
except Exception as e:
v = False
return v
#--------------------------
#--------------------------
if __name__ == '__main__':
a = hiraFile()
a.open("rlock.dat")
v = a.read(15)
print("read-v:",v)
v = a.getPos()
print("getPos-v:",v)
まぁこんなとこかな。