【问题标题】:How can I implement a POSIX file descriptor in Python 3?如何在 Python 3 中实现 POSIX 文件描述符?
【发布时间】:2012-01-30 19:54:32
【问题描述】:

我想编写一个可以充当真正的文件描述符的类。它的 .fileno() 方法应该返回一个文件描述符,该描述符提供 POSIX 系统期望的所有服务。

这是我第一次涉足 POSIX 系统编程,所以我可能对事情有很大的误解。

基本动机是希望使用内存中的 Python 对象作为 stdinstdout kwarg 到 subprocess.Popen 构造函数,而不必依赖临时或内存映射文件。但我对一些可以完成工作的巧妙技巧不感兴趣——我真的想要一个能够回答所有相关系统调用的 Python 实现。

【问题讨论】:

  • Python “包装” Posix 文件描述符。您拥有所需的所有访问权限。请定义“所有相关的系统调用”。支持打开、关闭、读取和写入。你还想要哪些?
  • @S.Lott:无论需要什么额外的调用来将 StringIO 对象(例如)作为stdinstdout kwarg 传递给subprocess.Popen
  • 什么?如果您想将 StringIO 与 subprocess.Popen 一起使用,也许您应该关闭此问题并询问您真正想知道的内容。

标签: python file-io python-3.x posix file-descriptor


【解决方案1】:

这是我第一次涉足 POSIX 系统编程,所以我可能对事情有很大的误解。

是的。

POSIX 文件描述符只是数字——它们不是对象,所以你不能覆盖它们的方法。例如,0、1 和 2 都是 [通常] 有效的文件描述符。

“相关系统调用”是内置在 Linux 内核中的。 Linux 内核本身维护一个列表,将文件描述符映射到某个内部内核对象(它确实有方法!),但是您不能从 Python 插入新的文件描述符。在内核空间中运行的代码与普通(“用户模式”)代码非常不同。

我能否建议您查看 subprocess.PIPE,以及 subprocess.Popen 对象上的 stdout/stdin/stderr 属性或communicate() 方法?这将让您启动一个子进程,读取它输出的数据,并完全控制发送给它的数据。 (我认为这是你真正想要做的......)。如果你很好奇,那么当你玩过这个之后,你可以查看 subprocess.py 源代码,看看它是如何工作的。

有一个 subprocess.PIPE here 的例子。

或者,如果您真的想用 Python 实现一个完整的文件系统,请查看FUSE,它是Python bindings。 FUSE 包含一个在内核中运行的 C 模块,并处理对某个目录的文件系统请求。它通过将它们传递给可以用 Python 编写的用户空间程序来处理它们。您可以从 单独的 Python 程序中打开这些文件,以获取它们的文件描述符。这有点复杂,可能不是初学者的最佳起点。

【讨论】:

    【解决方案2】:

    如果你想有一个类在传递给系统调用时可以用作文件,它需要有一个 fileno() ,它是一个真正的 OS 文件描述符。在不接触硬盘的情况下执行此操作的一种方法是使用管道,因为它们具有文件描述符,然后系统调用可以写入这些文件描述符。

    我确实为another answer 编写了一个使用这种技术做某事的类。它并没有真正做你想做的事情,但是使用管道的技术应该对你来说是可行的:

    import io
    import logging
    import os
    import select
    import subprocess
    import time
    import threading
    
    LOG_FILENAME = 'output.log'
    logging.basicConfig(filename=LOG_FILENAME,level=logging.DEBUG)
    
    class StreamLogger(io.IOBase):
        def __init__(self, level):
            self.level = level
            self.pipe = os.pipe()
            self.thread = threading.Thread(target=self._flusher)
            self.thread.start()
    
        def _flusher(self):
            self._run = True
            buf = b''
            while self._run:
                for fh in select.select([self.pipe[0]], [], [], 0)[0]:
                    buf += os.read(fh, 1024)
                    while b'\n' in buf:
                        data, buf = buf.split(b'\n', 1)
                        self.write(data.decode())
                time.sleep(1)
            self._run = None
    
        def write(self, data):
            return logging.log(self.level, data)
    
        def fileno(self):
            return self.pipe[1]
    
        def close(self):
            if self._run:
                self._run = False
                while self._run is not None:
                    time.sleep(1)
                os.close(self.pipe[0])
                os.close(self.pipe[1])
    

    【讨论】:

      【解决方案3】:

      你不能。 POSIX 文件描述符在 Python 世界之外的操作系统内核中被跟踪;你无法在 Python 代码中模拟它们。

      【讨论】:

        猜你喜欢
        • 2013-03-15
        • 1970-01-01
        • 2015-02-11
        • 2011-02-14
        • 1970-01-01
        • 1970-01-01
        • 2017-03-08
        • 1970-01-01
        相关资源
        最近更新 更多