【问题标题】:writing commands to mplayer subprocess with python 3 in windows在 windows 中使用 python 3 向 mplayer 子进程写入命令
【发布时间】:2016-02-26 02:29:52
【问题描述】:

我有一个...非常具体的问题。真的试图找到一个更广泛的问题,但找不到。

我正在尝试使用 mplayer 作为子进程来播放音乐(在 Windows 和 linux 上),并保留将命令传递给它的能力。我在 python 2.7 中使用subprocess.Popenp.stdin.write('pause\n') 完成了这一点。

然而,这似乎并没有在 Python 3 之旅中幸存下来。我必须使用 'pause\n'.encode()b'pause\n' 转换为 bytes,并且 mplayer 进程不会暂停。但是,如果我使用p.communicate,它似乎确实有效,但我已经排除了这种可能性,因为this question 声称每个进程只能调用一次。

这是我的代码:

p = subprocess.Popen('mplayer -slave -quiet "C:\\users\\me\\music\\Nickel Creek\\Nickel Creek\\07 Sweet Afton.mp3"', stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
time.sleep(1)
mplayer.stdin.write(b'pause\n')
time.sleep(1)
mplayer.stdin.write(b'pause\n')
time.sleep(1)
mplayer.stdin.write(b'quit\n')

看到此代码在 2.7 中有效(没有 bs),我只能假设将字符串编码为 bytes 会以某种方式更改字节值,以便 mplayer 无法再理解它?但是,当我尝试查看通过管道发送的确切字节时,它看起来是正确的。也可能是 Windows 管道表现得很奇怪。我用 cmd.exe 和 powershell 都试过了,因为我知道 powershell 将管道解释为 xml。我使用这段代码来测试通过管道输入的内容:

# test.py
if __name__ == "__main__":
    x = ''
    with open('test.out','w') as f:
        while (len(x) == 0 or x[-1] != 'q'):
            x += sys.stdin.read(1)
            print(x)
        f.write(x)

p = subprocess.Popen('python test.py', stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
p.stdin.write(b'hello there\ntest2\nq\n')

【问题讨论】:

    标签: python subprocess cross-platform mplayer


    【解决方案1】:

    看到这段代码在 2.7 中有效(没有bs),我只能假设将字符串编码为字节会以某种方式改变字节值,因此 mplayer 无法再理解它了?

    'pause\n' 在 Python 2 中的值完全b'pause\n' 相同——此外,您也可以在 Python 2 上使用 b'pause\n'(传达代码的意图)。 p>

    不同之处在于 Python 2 上的 bufsize=0 和因此 .write() 立即将内容推送到子进程,而 Python 3 上的 .write() 将其放在某个内部缓冲区中。添加.flush()调用,清空缓冲区。

    传递universal_newlines=True,以在 Python 3 上启用文本模式(然后您可以使用 'pause\n' 而不是 b'pause\n')。如果 mplayer 期望 os.newline 而不是 b'\n' 作为行尾,您可能还需要它。

    #!/usr/bin/env python3
    import time
    from subprocess import Popen, PIPE
    
    LINE_BUFFERED = 1
    filename = r"C:\Users\me\...Afton.mp3"
    with Popen('mplayer -slave -quiet'.split() + [filename],
               stdin=PIPE, universal_newlines=True, bufsize=LINE_BUFFERED) as process:
        send_command = lambda command: print(command, flush=True, file=process.stdin)
        time.sleep(1)
        for _ in range(2):
            send_command('pause')
            time.sleep(1)
        send_command('quit')
    

    无关:除非您从管道中读取,否则不要使用stdout=PIPE,否则您可能会挂起子进程。要丢弃输出,请改用stdout=subprocess.DEVNULL。见How to hide output of subprocess in Python 2.7

    【讨论】:

    • 谢谢!我很快就会检查这个解决方案......是的,我故意不使用universal_newlines,因为它会改变我的字符串的值,但我想我什至不认为mplayer的windows版本可能会期待一个\r\n,在事实上它可能是。是的,我一直在我的实际代码中使用 DEVNULL,不过感谢您的提示。
    • 换行符似乎无关紧要,但刷新流工作!非常感谢...叹息说实话我可能应该想到这一点。好的,谢谢
    猜你喜欢
    • 1970-01-01
    • 2013-03-29
    • 2012-09-05
    • 2013-07-30
    • 2010-11-05
    • 1970-01-01
    • 2021-06-13
    • 1970-01-01
    • 2017-05-30
    相关资源
    最近更新 更多