Windows NT Files -- Locking
Python's win32 access for file locking -- flock style
The need for file locking tends arise every so often. Some people
may be used to flock style locking, which has 4 basic cases:
shared,exclusive,blocking and non-blocking. Shared locking is
typically used when multiple people want to read a file. Exclusive is
for writing. Blocking means that the process will wait until it is
able to lock the file. Non-blocking will return immediately and tell
you the lock failed. In win32 the standard CreateFile api gives you
the ability to do exclusive or shared locking. However, what it does
not give you is the ability to switch between blocking/non-blocking
(it fails immediately -- does not block) To do that, you need to use
LockfileEx -- which can even lock a specific part of a file.
The basic procedure for doing this is to first call Createfile to
give you a filehandle. Then call LockfileEx with the filehandle.
Do whatever to the file. Call UnlockfileEx. Then close the filehandle.
(Some of you may want to close the filehandle to kill the locks, it
doesn't work that way with win32, at least according to the msdn)
Below is a class called Flock, which gives you exclusive/shared locking with non-blocking/blocking abilities. If you can think of any optimizations or changes, be sure to let me know.
CreateFile provides many options. It can be used for files,directories,mailslots,sockets, etc. In this case, we're only interested in standard files.
The C++ call looks like this:
HANDLE CreateFile( LPCTSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile );
The python call is virtually the same with:
PyHANDLE = CreateFile( fileName, desiredAccess , shareMode , attributes , creationDisposition , flagsAndAttributes , hTemplateFile )
The module win32con in python is invaluable for setting most of these attributes. Besides win32con, you need win32security to create a security attribute.
Example
Here is a basic example of the raw program:
import win32file import win32con import win32security import win32api import pywintypes highbits=0xffff0000 #high-order 32 bits of byte range to lock file="c:\\\\wilma.txt" secur_att = win32security.SECURITY_ATTRIBUTES() secur_att.Initialize() hfile=win32file.CreateFile( file,\\ win32con.GENERIC_READ|win32con.GENERIC_WRITE,\\ win32con.FILE_SHARE_READ|win32con.FILE_SHARE_WRITE,\\ secur_att,\\ #default win32con.OPEN_ALWAYS,\\ win32con.FILE_ATTRIBUTE_NORMAL , 0 ) ov=pywintypes.OVERLAPPED() #used to indicate starting region to lock win32file.LockFileEx(hfile,win32con.LOCKFILE_EXCLUSIVE_LOCK,0,highbits,ov) win32api.Sleep(4000) #do something here win32file.UnlockFileEx(hfile,0,highbits,ov) hfile.Close() <nl>Below, I have fleshed it out with a more useable Flock class. The code below works like this: You create an instance of the class, providing a filename. It will create/access the file in a default way and provide an hfile filehandle. If you don't want the default(shared/blocking), you can then specify in a dictionary what type of locking you want. Call the lock method on the file. Do whatever you want with the hfile filehandle, then call the unlock method which will remove the locks and close the filehandle. Looking at the code below, for desiredAccess and shareMode, I have both read and write on for most flexibility. The OPEN_ALWAYS means that it will either use the current file or create a new one if none is to be found. I use default security for the security attributes option. The lock method basically determines what lock flags should be used, depending on the type of locking you want and then calls LockFileEx. An interesting option to LockFileEx is self.highbits. You can use that to specify portions of a file to lock instead of the entire thing. When you're done with whatever you need to do, using the hfile, filehandle, if necessary, then call the unlock method, to remove the lock and close the filehandle. <nl>Now for some code| class Flock: def __init__(self,file): self.file=file self.type={'LOCK_EX':0,'LOCK_NB':0} secur_att = win32security.SECURITY_ATTRIBUTES() secur_att.Initialize() self.highbits=0xffff0000 #high-order 32 bits of byte range to lock #make a handel with read/write and open or create if doesn't exist self.hfile=win32file.CreateFile( self.file,\\ win32con.GENERIC_READ|win32con.GENERIC_WRITE,\\ win32con.FILE_SHARE_READ|win32con.FILE_SHARE_WRITE,\\ secur_att,\\ win32con.OPEN_ALWAYS,\\ win32con.FILE_ATTRIBUTE_NORMAL , 0 ) def lock(self): if self.type['LOCK_EX']: #exclusive locking if self.type['LOCK_NB']: #don't wait, non-blocking lock_flags=win32con.LOCKFILE_EXCLUSIVE_LOCK|win32con.LOCKFILE_FAIL_IMMEDIATELY else: #wait for lock to free lock_flags=win32con.LOCKFILE_EXCLUSIVE_LOCK else: #shared locking if self.type['LOCK_NB']: #don't wait, non-blocking lock_flags=win32con.LOCKFILE_FAIL_IMMEDIATELY else:#shared lock wait for lock to free lock_flags=0 self.ov=pywintypes.OVERLAPPED() #used to indicate starting region to lock win32file.LockFileEx(self.hfile,lock_flags,0,self.highbits,self.ov) def unlock(self): win32file.UnlockFileEx(self.hfile,0,self.highbits,self.ov) #remove locks self.hfile.Close() l=Flock("c:\\\\a3.txt") l.type['LOCK_EX']=0 l.type['LOCK_NB']=0 print 'calling lock' l.lock() print 'now locked ' win32api.Sleep(1000) l.unlock() print 'now unlocked'Have a great time with programming with python!
John Nielsen nielsenjf@my-deja.com