如何在Python 3中实现POSIX文件描述符?

时间:2011-12-30 21:04:54

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

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

这是我第一次涉足POSIX系统编程,所以我可能会误解事情。

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

3 个答案:

答案 0 :(得分:2)

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

答案 1 :(得分: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])

答案 2 :(得分:0)

  

这是我第一次涉足POSIX系统编程,所以我可能会误解事情。

是的。

POSIX文件描述符只是数字 - 它们不是对象,因此您无法覆盖它们的方法。例如,0,1和2都是[通常]有效的文件描述符。

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

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

有一个subprocess.PIPE here的例子。

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