微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何将写入文件的数据流式传输到标准输出

如何解决如何将写入文件的数据流式传输到标准输出

我用 C 实现了共享库,它提供了一个函数 F。每次我调用 F 时,它都会将其输出记录在文件 error.log 中。

现在我正在尝试从 python 脚本中捕获 F 生成输出(我使用的是 python 2.7.5,由于我无法控制的原因,我无法更改)。

我想将写入 error.log 的数据流式传输到其他文件stdout。我不能只是打开文件并解析它,因为它登录了更多的东西,包括 F 之前和之后运行的输出。我只对特定的执行感兴趣,我无法仅从日志中识别出该执行。这就是我尝试捕获输出的原因。

我尝试从 python 打开 error.log,然后更改文件描述符以使其指向 stdout,但这似乎不起作用(我对 stdoutstderr 并且确实有效)。

我做的大概是

with open('error.log') as logfile:
    with redirect_output(logfile,sys.stdout):
        function_implemented_in_C()

其中 redirect_output 是我为执行重定向而实现的上下文管理器:

@contextmanager
def redirect_output(orig,dest):
    orig_fd = orig.fileno()
    with os.fdopen(os.dup(orig_fd)) as old_orig_fd:
        os.dup2(dest.fileno(),orig_fd)
    
    try:
        yield orig
    finally:
        # clean and restore fd's

我无法让它工作。知道我做错了什么吗?

更新:

我将问题简化为一个简单的脚本,但它似乎仍然不起作用。我猜这与从共享库 (?) 中的函数生成的数据有关,因为如果我执行相同操作但从从 python 打开的文件重定向 write 调用,它可以工作。这个例子工作正常:

import sys
import os

def foo():
    f = open('dummy.txt','wb',buffering=0)
    os.dup2(sys.stdout.fileno(),f.fileno())
    f.write('some test data\n')
    f.close()

if __name__ == '__main__':
    foo()

但这没有

import sys
import os

def foo():
    f = open('error.log',f.fileno())
    function_implemented_in_C()
    f.close()

if __name__ == '__main__':
    foo()

解决方法

我正在回答我自己的问题,以防有人遇到同样的问题。

这里的问题是在 error.log 中产生输出的 C 函数会启动一个不同的进程来执行任务。这使得无法轻松地将文件写入重定向到 stdout,因为文件描述符是特定于进程的。

因此,如果您的函数碰巧使用相同的过程产生输出,那么以下应该可以工作

import sys
import os

def foo():
    f = open('dummy.txt','wb',buffering=0)
    os.dup2(sys.stdout.fileno(),f.fileno())
    f.write('some test data\n')
    f.close()

if __name__ == '__main__':
    foo()

如果不是这种情况,那么您可以通过设置从文件中读取的循环来解决问题,以便获取新写入的数据。类似的东西(我没有尝试过这段代码,所以它无法运行):

from multiprocessing import Process,Pipe

def foo(filename,pipe_conn):
    with open(filename) as f:
        while True:
            line = f.readline()
            do_something(line)
            if pipe_conn.poll(0.01):
                break

def bar(pipe_conn):
    function_implemented_in_C()
    pipe_conn.send(['done'])
    pipe_conn.close()

if __name__ == '__main__':
    parent_conn,child_conn = Pipe()
    p = Process(target=bar,args=(child_conn,))
    p.start()
    foo(parent_conn)
    p.join()

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。