File Locking Using a Cross-Platform API

艾敏学
2023-12-01

File Locking Using a Cross-Platform API

获得平台无关的文件锁

Credit: Jonathan Feinberg, John Nielsen

 

问题 Problem

 

You need to lock files in a cross-platform way between NT and Posix, but the Python standard library offers only platform-specific ways to lock files.

Python标准库未提供锁定文件的平台无关的方法,需要自己编写这样的平台无关(在NT和Posix之间)的锁定文件的代码。

 

解决 Solution

 

When the Python standard library itself doesn't offer a cross-platform solution, it's often possible to implement one ourselves:

当Python标准库未提供某功能的平台无关的方法是,经常可以自己实现:

 

切换行号显示
   1 import os
   2 
   3 # needs win32all to work on Windows
   4 if os.name == 'nt':
   5     import win32con, win32file, pywintypes
   6     LOCK_EX = win32con.LOCKFILE_EXCLUSIVE_LOCK
   7     LOCK_SH = 0 # the default
   8     LOCK_NB = win32con.LOCKFILE_FAIL_IMMEDIATELY
   9     _ _overlapped = pywintypes.OVERLAPPED(  )
  10 
  11     def lock(file, flags):
  12         hfile = win32file._get_osfhandle(file.fileno(  ))
  13         win32file.LockFileEx(hfile, flags, 0, 0xffff0000, _ _overlapped)
  14 
  15     def unlock(file):
  16         hfile = win32file._get_osfhandle(file.fileno(  ))
  17         win32file.UnlockFileEx(hfile, 0, 0xffff0000, _ _overlapped)
  18 elif os.name == 'posix':
  19     from fcntl import LOCK_EX, LOCK_SH, LOCK_NB
  20 
  21     def lock(file, flags):
  22         fcntl.flock(file.fileno(  ), flags)
  23 
  24     def unlock(file):
  25         fcntl.flock(file.fileno(  ), fcntl.LOCK_UN)
  26 else:
  27     raise RuntimeError("PortaLocker only defined for nt and posix platforms")

 

 

讨论 Discussion

 

If you have multiple programs or threads that may want to access a shared file, it's wise to ensure that accesses are synchronized, so that two processes don't try to modify the file contents at the same time. Failure to do so could corrupt the entire file in some cases.

如果有多个程序或线程需要访问一个共享文件,明智的处理是保证访问同步化, 这样2个进程不会同时修改文件. 否则如果没有同步处理,在一些情况下,整个程序可能会崩溃。

This recipe supplies two functions, lock and unlock, that request and release locks on a file, respectively. Using the portalocker.py module is a simple matter of calling the lock function and passing in the file and an argument specifying the kind of lock that is desired:

脚本提供了两个函数: lock 和unlock,分别对文件加锁和释放锁。使用portalocker.py模块很简单,仅需要调用lock函数,传递文件参数和欲加的锁类型参数:

LOCK_SH A shared lock (the default value). This denies all processes write access to the file, including the process that first locks the file. All processes can read the locked file.

共享锁(默认值)。所有进程没有写访问权限,即使是加锁进程也没有。所有进程有读访问权限。

LOCK_EX An exclusive lock. This denies all other processes both read and write access to the file.

排他锁。 除加锁进程外其他进程没有对已加锁文件读写访问权限。

LOCK_NB A nonblocking lock. If this value is specified, the function returns immediately if it is unable to acquire the requested lock. Otherwise, it waits. LOCK_NB can be ORed with either LOCK_SH or LOCK_EX.

非阻塞锁。 如果指定此参数,函数不能获得文件锁就立即返回,否则,函数会等待获得文件锁。LOCK_NB可以同LOCK_SH或LOCK_NB进行or运算。

For example:

例如:

切换行号显示
   1 import portalocker
   2 file = open("somefile", "r+")
   3 portalocker.lock(file, portalocker.LOCK_EX)

 

The implementation of the lock and unlock functions is entirely different on Unix-like systems (where they can rely on functionality made available by the standard fcntl module) and on Windows systems (where they must use the win32file module, part of the very popular win32all package of Windows-specific extensions to Python, authored by Mark Hammond). But the important thing is that, despite the differences in implementation, the functions (and the flags you can pass to the lock function) behave in the same way across platforms. Such cross-platform packaging of differently implemented but equivalent functionality is what lets you write cross-platform applications, which is one of Python's strengths.

lock和unlock地实现在类Unix系统和Windows系统下的完全不同:类Unix系统下依赖于标准模块fcntl提供的功能,Windows系统下使用了非常流行的由Mark Hammond实现的Windows下特定扩展中的win32all模块提供的功能。虽然不同系统下的实现不同,但重要的是,不同平台下文件加解锁的行为是相同的。这样,将不同的实现但相同的行为按照平台无关的方式用模块封装起来,是Python的一大优势:可以编写平台无关的应用。

When you write a cross-platform program, it's nice if the functionality that your program uses is, in turn, encapsulated in a cross-platform way. For file locking in particular, this is helpful to Perl users, who are used to an essentially transparent lock system call across platforms. More generally, if os.name== just does not belong in application-level code. It should ideally always be in the standard library or an application-independent module, as it is here.

当编写跨平台的程序时,如果使用的功能函数已经是经过平台无关的封装处理的,那样会很舒服。特别的,对于文件加锁,perl程序员就不用费心了: Perl提供了透明的跨平台的文件加锁功能。 更一般的,如果os.name不应该出现在应用级别的代码中 ,那么最好它们应该位于Python标准库中 或者在应用无关的模块中(就像 这里的脚本一样).

 类似资料:

相关阅读

相关文章

相关问答