使用open()打开文件时使用的共享模式

时间:2013-12-02 12:30:31

标签: python windows

我在open()函数的参数中看不到任何内容,它们允许指定文件的共享方式。因此我怀疑该文件将尽可能地被共享。具体做法是:

  1. 打开文件进行阅读时,其共享模式将允许后续打开操作打开文件进行读取,但不能写入。
  2. 当文件打开进行写入时,其共享模式将拒绝后续打开操作以打开文件进行读写。
  3. 在我看来,这是最合乎逻辑的实施方式。我的假设是否正确?

    更新:Martijn Pieters表示答案取决于操作系统。所以,为了这个问题,我的目标操作系统是Windows。

2 个答案:

答案 0 :(得分:4)

Python在打开文件时在内部使用_wfopen()(Python 2 open()函数)或_wopen()(Python 3和io.open()),这两者都不允许指定任何共享标志。因此,共享被设置为默认值,并且该默认值似乎没有记录。

如果您想自己设置共享模式,如果要打开指定共享模式的文件,则必须使用msvcrt.open_osfhandle()

有一个patch in the Python issue tracker实现了sharing模块,说明了如何执行此操作。 只是来自该补丁的开启者,有点简化,是:

import os
import msvcrt
import _winapi

CREATE_NEW                  = 1
CREATE_ALWAYS               = 2
OPEN_EXISTING               = 3
OPEN_ALWAYS                 = 4
TRUNCATE_EXISTING           = 5
FILE_SHARE_READ             = 0x00000001
FILE_SHARE_WRITE            = 0x00000002
FILE_SHARE_DELETE           = 0x00000004
FILE_SHARE_VALID_FLAGS      = 0x00000007
FILE_ATTRIBUTE_READONLY     = 0x00000001
FILE_ATTRIBUTE_NORMAL       = 0x00000080
FILE_ATTRIBUTE_TEMPORARY    = 0x00000100
FILE_FLAG_DELETE_ON_CLOSE   = 0x04000000
FILE_FLAG_SEQUENTIAL_SCAN   = 0x08000000
FILE_FLAG_RANDOM_ACCESS     = 0x10000000
GENERIC_READ                = 0x80000000
GENERIC_WRITE               = 0x40000000
DELETE                      = 0x00010000
NULL                        = 0

_ACCESS_MASK = os.O_RDONLY | os.O_WRONLY | os.O_RDWR
_ACCESS_MAP  = {os.O_RDONLY : GENERIC_READ,
                os.O_WRONLY : GENERIC_WRITE,
                os.O_RDWR   : GENERIC_READ | GENERIC_WRITE}

_CREATE_MASK = os.O_CREAT | os.O_EXCL | os.O_TRUNC
_CREATE_MAP  = {0                                   : OPEN_EXISTING,
                os.O_EXCL                           : OPEN_EXISTING,
                os.O_CREAT                          : OPEN_ALWAYS,
                os.O_CREAT | os.O_EXCL              : CREATE_NEW,
                os.O_CREAT | os.O_TRUNC | os.O_EXCL : CREATE_NEW,
                os.O_TRUNC                          : TRUNCATE_EXISTING,
                os.O_TRUNC | os.O_EXCL              : TRUNCATE_EXISTING,
                os.O_CREAT | os.O_TRUNC             : CREATE_ALWAYS}


def os_open(file, flags, mode=0o777,
            *, share_flags=FILE_SHARE_VALID_FLAGS):
    '''
    Replacement for os.open() allowing moving or unlinking before closing
    '''
    if not isinstance(flags, int) and mode >= 0:
        raise ValueError('bad flags: %r' % flags)

    if not isinstance(mode, int) and mode >= 0:
        raise ValueError('bad mode: %r' % mode)

    if share_flags & ~FILE_SHARE_VALID_FLAGS:
        raise ValueError('bad share_flags: %r' % share_flags)

    access_flags = _ACCESS_MAP[flags & _ACCESS_MASK]
    create_flags = _CREATE_MAP[flags & _CREATE_MASK]
    attrib_flags = FILE_ATTRIBUTE_NORMAL

    if flags & os.O_CREAT and mode & ~0o444 == 0:
        attrib_flags = FILE_ATTRIBUTE_READONLY

    if flags & os.O_TEMPORARY:
        share_flags |= FILE_SHARE_DELETE
        attrib_flags |= FILE_FLAG_DELETE_ON_CLOSE
        access_flags |= DELETE

    if flags & os.O_SHORT_LIVED:
        attrib_flags |= FILE_ATTRIBUTE_TEMPORARY

    if flags & os.O_SEQUENTIAL:
        attrib_flags |= FILE_FLAG_SEQUENTIAL_SCAN

    if flags & os.O_RANDOM:
        attrib_flags |= FILE_FLAG_RANDOM_ACCESS

    h = _winapi.CreateFile(file, access_flags, share_flags, NULL,
                           create_flags, attrib_flags, NULL)
    return msvcrt.open_osfhandle(h, flags | os.O_NOINHERIT)

答案 1 :(得分:2)

  

当文件打开进行写入时,其共享模式将拒绝后续打开操作以打开文件进行读写。

假。没有获得锁。您可以尝试使用两个不同的cmd窗口:

首先

python -c "import time; f = open('tst','wb'); f.write('1'); time.sleep(3); f.write('333'); f.close"

第二,第一次正在运行

python -c "with open('tst','wb') as f: f.write('22')"

1333文件中生成tst。在第一次写入第一个脚本后,使用f.flush()刷新写入会导致2333。错过的数据会被\x00字符替换,您可以查看它,例如将f.write('1')替换为f.write('1'*10**6)