【问题标题】:Shared file access between Python and MatlabPython 和 Matlab 之间的共享文件访问
【发布时间】:2015-05-19 01:37:08
【问题描述】:

我有一个写入 .csv 文件的 Matlab 应用程序和一个从中读取的 Python 脚本。这些操作同时发生并在它们各自的时期(不一定相同)。所有这些都在 Windows 7 上运行。

我想知道:

  1. 操作系统是否会固有地提供某种锁定机制,以便两个应用程序(Matlab 或 Python)中只有一个可以访问共享文件?
  2. 在 Python 应用程序中,如何检查文件是否已被 Matlab 应用程序“打开”?什么是循环结构,以便 Python 应用程序在获得读取文件的访问权限之前被阻塞?

【问题讨论】:

  • 如果文件在 Windows 上打开,您在尝试写入时不会出错吗?
  • 这实际上只是一个可能的用例。稍后我可能也会反过来,即 Python 写入而 Matlab 读取。那么 _winapi.CreateFile 方法在这种情况下也能工作吗?

标签: python windows matlab file shared


【解决方案1】:

我不确定窗口用于锁定文件的 API

这是一个可能的解决方案:

  1. 当 matlab 打开文件时,您会创建一个名为“data.lock”的空文件或类似的东西。

  2. 当 python 尝试读取文件时,它会检查锁定文件,如果存在,那么它将休眠给定的时间间隔。

  3. matlab处理完文件后,可以删除“data.lock”文件。

它是一种编程解决方案,但它比挖掘 windows api 并在 matlab 和 python 中找到正确的调用更简单。

【讨论】:

  • 至于检查文件是否已经打开,尝试打开并捕获错误会更容易。
  • 当然,这是我通过使用“data.lock”作为锁定对象来管理文件访问的一种方法。我正在寻找使用 Python 和 Matlab 的固有方法来处理这个问题的解决方案。
  • 我对 python 非常熟悉,如果不使用外部库,您将无法在 python 中找到用于此特定任务的内置方法。这是一个外部库related question。希望这会有所帮助。
  • LeBarton :我正在考虑您的解决方案,因为它非常简单。但是就像您维护“data.lock”以防止 Python 在 Matlab 正在写入时读取的方式一样,我不应该有另一个锁来防止 Matlab 在 Python 正在读取时写入吗?
  • 如果脚本可以竞争资源,那么您可以让 matlab 脚本检查锁。您可以做两个锁定文件或只做一个。您只需要以这样一种方式对其进行编码,即脚本知道它对文件有一个锁定,并且无论脚本正常结束还是发生致命异常,脚本都可以保证释放该锁定。
【解决方案2】:

如果 Python 只是读取文件,我相信您必须将其锁定在 MATLAB 中,因为来自 Python 的只读打开调用可能不会失败。我不知道如何做到这一点,你可能想阅读这个问题atomically creating a file lock in MATLAB (file mutex)

但是,如果你只是简单地使用 python 来消费数据,你是否考虑过使用套接字而不是文件?

【讨论】:

    【解决方案3】:

    在 Python 端的 Windows 中,可以使用特定的共享模式(直接或通过 CRT 间接调用)CreateFile。例如,如果所需的共享模式是FILE_SHARE_READ,则如果文件已打开以进行写入,则打开将失败。如果后一个调用成功,那么将来打开文件进行写入的尝试将失败(例如在 Matlab 中)。

    Windows CRT 函数_wsopen_s 允许设置共享模式。您可以在 Python 3 opener 中使用 ctypes 调用它:

    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。这需要更多的工作才能从传入的flags 中获取文件mode,反之亦然。

    【讨论】:

    • 感谢您的所有努力,但我发现其他解决方案更简单!
    • 是的,另一个解决方案更简单,因为您只关心控制 Matlab 和 Python 脚本之间的访问。设置操作系统文件共享模式是一种通用的解决方案。
    猜你喜欢
    • 1970-01-01
    • 2013-04-16
    • 2023-01-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-01
    相关资源
    最近更新 更多