В Windows со стороны Python CreateFile
можно вызвать (прямо или косвенно через ЭЛТ) в определенном режиме совместного доступа. Например, если желаемый режим совместного доступа равен FILE_SHARE_READ
, тогда сбой будет открыт, если файл уже открыт для записи. Если последний вызов вместо этого преуспевает, то неудачная попытка открыть файл для записи завершится неудачно (например, в Matlab).
Функция Windows CRT _wsopen_s
позволяет установить режим совместного доступа. Вы можете назвать это с ctypes в Python 3 opener
:
import sys
import os
import ctypes as ctypes
import ctypes.util
__all__ = ['shdeny', 'shdeny_write', 'shdeny_read']
_SH_DENYRW = 0x10 # deny read/write mode
_SH_DENYWR = 0x20 # deny write mode
_SH_DENYRD = 0x30 # deny read
_S_IWRITE = 0x0080 # for O_CREAT, a new file is not readonly
if sys.version_info[:2] < (3,5):
_wsopen_s = ctypes.CDLL(ctypes.util.find_library('c'))._wsopen_s
else:
# find_library('c') may be deprecated on Windows in 3.5, if the
# universal CRT removes named exports. The following probably
# isn't future proof; I don't know how the '-l1-1-0' suffix
# should be handled.
_wsopen_s = ctypes.CDLL('api-ms-win-crt-stdio-l1-1-0')._wsopen_s
_wsopen_s.argtypes = (ctypes.POINTER(ctypes.c_int), # pfh
ctypes.c_wchar_p, # filename
ctypes.c_int, # oflag
ctypes.c_int, # shflag
ctypes.c_int) # pmode
def shdeny(file, flags):
fh = ctypes.c_int()
err = _wsopen_s(ctypes.byref(fh),
file, flags, _SH_DENYRW, _S_IWRITE)
if err:
raise IOError(err, os.strerror(err), file)
return fh.value
def shdeny_write(file, flags):
fh = ctypes.c_int()
err = _wsopen_s(ctypes.byref(fh),
file, flags, _SH_DENYWR, _S_IWRITE)
if err:
raise IOError(err, os.strerror(err), file)
return fh.value
def shdeny_read(file, flags):
fh = ctypes.c_int()
err = _wsopen_s(ctypes.byref(fh),
file, flags, _SH_DENYRD, _S_IWRITE)
if err:
raise IOError(err, os.strerror(err), file)
return fh.value
Например:
if __name__ == '__main__':
import tempfile
filename = tempfile.mktemp()
fw = open(filename, 'w')
fw.write('spam')
fw.flush()
fr = open(filename)
assert fr.read() == 'spam'
try:
f = open(filename, opener=shdeny_write)
except PermissionError:
fw.close()
with open(filename, opener=shdeny_write) as f:
assert f.read() == 'spam'
try:
f = open(filename, opener=shdeny_read)
except PermissionError:
fr.close()
with open(filename, opener=shdeny_read) as f:
assert f.read() == 'spam'
with open(filename, opener=shdeny) as f:
assert f.read() == 'spam'
os.remove(filename)
В Python 2 вы должны объединить вышеуказанные открывалки с os.fdopen
, например:
f = os.fdopen(shdeny_write(filename, os.O_RDONLY|os.O_TEXT), 'r')
Или определите оболочку sopen
, которая позволяет передавать режим совместного доступа явно и вызывает os.fdopen
, чтобы вернуть Python 2 file
.Для этого потребуется немного больше работы, чтобы получить файл mode
из полученного в flags
или наоборот.
Если файл открыт на окнах, вы не получите сообщение об ошибке? –
Ну, это на самом деле только один возможный случай использования. Позже у меня может быть и другое, а то, как пишет Python, в то время как Matlab читает. Так будет ли работать метод _winapi.CreateFile в таком сценарии? – JDD