简体   繁体   English

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

[英]How can I implement a POSIX file descriptor in Python 3?

I'd like to write a class that can behave as a bona fide file descriptor. 我想写一个可以表现为真正的文件描述符的类。 Its .fileno() method should return a file descriptor that provides all the services a POSIX system expects. 它的.fileno()方法应返回一个文件描述符,它提供POSIX系统所需的所有服务。

This is my first foray into POSIX system programming, so I could be misunderstanding things quite badly. 这是我第一次涉足POSIX系统编程,所以我可能会误解事情。

The underlying motivation is the desire to use an in-memory Python object as the stdin or stdout kwarg to the subprocess.Popen constructor without having to rely on temporary or memory-mapped files. 底层动机是使用一个内存Python对象作为欲望stdinstdout kwarg到subprocess.Popen构造,而不必依赖于临时或存储器映射的文件。 But I'm not interested in some clever trick that would get the job done -- I really want to have a Python implementation capable of answering all the relevant system calls. 但是我对一些聪明的技巧不感兴趣 - 我真的希望有一个能够回答所有相关系统调用的Python实现。

You can't. 你不能。 POSIX file descriptors are tracked in the operating system kernel, outside the world of Python; 在Python世界之外的操作系统内核中跟踪POSIX文件描述符; you can't simulate them in Python code. 你无法在Python代码中模拟它们。

If you want to have a class that can be used as a file when passed to system calls, it needs to have a fileno() that is a real OS file descriptors. 如果你想要一个可以在传递给系统调用时用作文件的类,它需要有一个fileno(),它是一个真正的OS文件描述符。 One way of doing this without touching a hard-disk is to use pipes, because they have file descriptors, and the system calls can then write to these file descriptors. 在不触及硬盘的情况下执行此操作的一种方法是使用管道,因为它们具有文件描述符,然后系统调用可以写入这些文件描述符。

I did write a class that did something using this technique for another answer . 我写了一个类,用另一个答案使用这种技术做了一些事情。 It doesn't really do what you want to do, but the technique of using pipes should be doable for you to: 它并没有真正做你想做的事情,但使用管道的技术应该可以让你:

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])

This is my first foray into POSIX system programming, so I could be misunderstanding things quite badly. 这是我第一次涉足POSIX系统编程,所以我可能会误解事情。

Yep. 是的。

POSIX file descriptors are just numbers - they're not objects, so you can't override their methods. POSIX文件描述符只是数字 - 它们不是对象,因此您无法覆盖它们的方法。 For example, 0, 1, and 2 are all [usually] valid file descriptors. 例如,0,1和2都是[通常]有效的文件描述符。

"the relevant system calls" are built in to the Linux kernel. “相关系统调用”内置于Linux内核中。 The Linux kernel itself maintains a list that maps file descriptors to some internal kernel object (which does have methods!) but you can't insert a new file descriptor from Python. Linux内核本身维护一个列表,将文件描述符映射到某个内部内核对象(它有方法!),但是你不能从Python插入新的文件描述符。 Code running in kernel space is very different from normal ("user mode") code. 在内核空间中运行的代码与普通(“用户模式”)代码非常不同。

Can I suggest you look at subprocess.PIPE, and either the stdout/stdin/stderr properties or the communicate() method on subprocess.Popen objects? 我可以建议您查看subprocess.PIPE,以及stdout / stdin / stderr属性或subprocess.Popen对象上的communic()方法吗? This will let you start a subprocess, read the data that it outputs, and have full control of the data that gets sent to it. 这将允许您启动子进程,读取它输出的数据,并完全控制发送给它的数据。 (I think this is what you're really trying to do...). (我认为这是你真正想做的......)。 If you're curious, then when you've played with this you can look at the subprocess.py source code to see how it works. 如果你很好奇,那么当你玩这个时,你可以查看subprocess.py源代码,看看它是如何工作的。

There's an example of subprocess.PIPE here . 有subprocess.PIPE的例子在这里

Alternatively, if you actually want to implement a full filesystem in Python, look at FUSE , and it's Python bindings . 或者,如果您确实想在Python中实现完整的文件系统,请查看FUSE ,它是Python绑定 FUSE includes a C module that runs in the kernel, and handles filesystem requests for a certain directory. FUSE包含一个在内核中运行的C模块,并处理某个目录的文件系统请求。 It handles them by passing them to a userspace program, which could be written in Python. 它通过将它们传递给用户空间程序来处理它们,该程序可以用Python编写。 You can open those files from a separate Python program, to get a file descriptor to them. 您可以从单独的 Python程序中打开这些文件,以获取文件描述符。 This is kind of complex, and probably not the best place for a beginner to start. 这有点复杂,可能不是初学者开始的最佳场所。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM