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

5
我想编写一个类,它可以表现为一个真正的文件描述符。它的.fileno()方法应该返回一个文件描述符,提供所有POSIX系统所期望的服务。
这是我第一次涉足POSIX系统编程,所以我可能会非常误解事情。
底层动机是希望使用内存中的Python对象作为subprocess.Popen构造函数的stdin或stdout关键字参数,而不必依赖于临时或内存映射文件。但我不感兴趣的是一些聪明的技巧,只是为了完成工作 - 我真的想有一个Python实现,能够回答所有相关的系统调用。

Python“包装”了Posix文件描述符。您拥有所需的所有访问权限。请定义“所有相关系统调用”。支持打开、关闭、读取和写入。您还需要哪些? - S.Lott
@S.Lott:无论需要进行多少额外的调用,以便将StringIO对象(例如)作为subprocess.Popenstdinstdout关键字参数传递。 - anon
1
如果你想在subprocess.Popen中使用StringIO,也许你应该关闭这个问题并问出你真正想知道的内容 - S.Lott
3个回答

2

不行。POSIX文件描述符在操作系统内核中跟踪,超出了Python的范畴;你无法在Python代码中模拟它们。


2
如果您想要一个可以在传递给系统调用时用作文件的类,则需要具有fileno(),它是真实的操作系统文件描述符。一种无需触摸硬盘就可以做到这一点的方法是使用管道,因为它们具有文件描述符,系统调用可以将数据写入这些文件描述符。
我曾经为另一个答案编写过一个使用此技术的类。它并不能完全满足您的需求,但使用管道的技术对您来说应该是可行的。
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])

0
这是我第一次涉足POSIX系统编程,所以我可能会非常误解事情。
没错。
POSIX文件描述符只是数字 - 它们不是对象,因此您无法覆盖它们的方法。例如,0、1和2都是[通常]有效的文件描述符。
“相关的系统调用”内置于Linux内核中。Linux内核本身维护一个将文件描述符映射到某些内部内核对象(具有方法!)的列表,但您无法从Python插入新的文件描述符。在内核空间运行的代码与正常(“用户模式”)代码非常不同。
我可以建议您查看subprocess.PIPE,并查看subprocess.Popen对象上的stdout / stdin / stderr属性或communicate()方法?这将使您启动子进程,读取其输出的数据,并完全控制发送到它的数据。(我认为这才是您真正想做的...)。如果您感到好奇,那么当您玩过这个之后,您可以查看subprocess.py源代码以了解其工作原理。

这里有一个subprocess.PIPE的例子在这里

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接