• Python 3 利用 subprocess 实现管道( pipe )交互操作读/写通信


    这里我们用Windows下的shell来举例:

    from subprocess import * #因为是举例,就全部导入了

    为了方便你理解,我们用一个很简单的一段代码来说明:

    可以看见我们利用Popen实例化了一个p,创建了子程序cmd.exe,然后我们给他的的Stdin(标准输入流)Stdout(标准输出流);

    同时使用了subprocess.PIPE 作为参数,这个是一个特殊值,用于表明这些通道要开放(在Python3.5,加入了run()方法来进行更好的操作)

     

    然后我们继续

    这些信息是不是很眼熟?这都是cmd的标准输出!

    然后就会输出这些:

    我们刚刚所写入的信息"echo Hellwworlds "已经被写入了,看起来确实成功了!

    注意一下我们使用了 p.stdin.flush() 来对输入缓存区进行刷新,输出的信息也需要一个 " ",至少在 Windows 系统下必须这样做,否则只刷新(p.stdin.flush)的话是无效的;

    我们到底做了什么?


    我们成功的创建了子程序 cmd.exe,并且写入"echo Hellwworlds " ,然后cmd获取了并且执行,于是返回 Hellwworlds,这就是一次很简单的读写交互!

     

    更高级的使用


    既然我们已经可以简单的读写了,那么加点for和threading 吧,味道也许更佳喔~

     1 #run.py  
     2 
     3 from subprocess import * 
     4 import threading 
     5 import time
     6 
     7 p =Popen('cmd.exe',shell=True,stdin=PIPE,stdout=PIPE)
     8 
     9 def run():
    10     global p
    11     while True:
    12         line = p.stdout.readline() 
    13         if not line:  #空则跳出
    14             break
    15         print(">>>>>>",line.decode("GBK"))
    16 
    17     print("look up!!! EXIT ===")   #跳出
    18 
    19 
    20 w =threading.Thread(target=run)
    21 
    22 p.stdin.write("echo HELLW_WORLD!
    ".encode("GBK"))
    23 p.stdin.flush()
    24 time.sleep(1) #延迟是因为等待一下线程就绪
    25 p.stdin.write("exit
    ".encode("GBK"))
    26 p.stdin.flush()
    27 
    28 w.start()

    很好很好,猜猜输出什么?

    有很多换行的原因是cmd返回的结果有换行,然后print输出会加一个换行,所以就换了两行,你可以考虑使用 sys.stdout.write 来输出,这样就没有附加的换行了

    这样的话,你可以制作一个基础的读写了,那么我们开始封装吧。

    封装Pipe


     不废话了,直接上代码,如果你真的想学会的话,还请认真自己读读代码。

     110行

    我们实现了将所有的过程集中在一个类里面,并且可以定义三个参数,退出反馈函数,就绪反馈函数和输出反馈函数。

      1 # -*- coding:utf-8 -*-
      2 
      3 import subprocess  
      4 import sys
      5 import threading
      6 
      7 class LoopException(Exception):
      8     """循环异常自定义异常,此异常并不代表循环每一次都是非正常退出的"""
      9     def __init__(self,msg="LoopException"):
     10         self._msg=msg
     11 
     12     def __str__(self):
     13         return self._msg
     14 
     15 
     16 
     17 class SwPipe():
     18     """
     19     与任意子进程通信管道类,可以进行管道交互通信
     20     """
     21     def __init__(self,commande,func,exitfunc,readyfunc=None,
     22         shell=True,stdin=subprocess.PIPE,stdout=subprocess.PIPE,stderr=subprocess.PIPE,code="GBK"):
     23         """
     24         commande 命令
     25         func 正确输出反馈函数
     26         exitfunc 异常反馈函数
     27         readyfunc 当管道创建完毕时调用
     28         """
     29         self._thread = threading.Thread(target=self.__run,args=(commande,shell,stdin,stdout,stderr,readyfunc))
     30         self._code = code
     31         self._func = func
     32         self._exitfunc = exitfunc
     33         self._flag = False
     34         self._CRFL = "
    "
     35 
     36     def __run(self,commande,shell,stdin,stdout,stderr,readyfunc):
     37         """ 私有函数 """
     38         try:
     39             self._process = subprocess.Popen(
     40                 commande,
     41                 shell=shell,
     42                 stdin=stdin,
     43                 stdout=stdout,
     44                 stderr=stderr
     45                 )  
     46         except OSError as e:
     47             self._exitfunc(e)
     48         fun = self._process.stdout.readline
     49         self._flag = True
     50         if readyfunc != None:
     51             threading.Thread(target=readyfunc).start() #准备就绪
     52         while True:
     53             line = fun()  
     54             if not line:  
     55                 break
     56             try:
     57                 tmp = line.decode(self._code)
     58             except UnicodeDecodeError:
     59                 tmp =  
     60                 self._CRFL + "[PIPE_CODE_ERROR] <Code ERROR: UnicodeDecodeError>
    " 
     61                 + "[PIPE_CODE_ERROR] Now code is: " + self._code + self._CRFL
     62             self._func(self,tmp)
     63 
     64         self._flag = False
     65         self._exitfunc(LoopException("While Loop break"))   #正常退出
     66 
     67 
     68     def write(self,msg):
     69         if self._flag:
     70             #请注意一下这里的换行
     71             self._process.stdin.write((msg + self._CRFL).encode(self._code)) 
     72             self._process.stdin.flush()
     73             #sys.stdin.write(msg)#怎么说呢,无法直接用代码发送指令,只能默认的stdin
     74         else:
     75             raise LoopException("Shell pipe error from '_flag' not True!")  #还未准备好就退出
     76 
     77 
     78     def start(self):
     79         """ 开始线程 """
     80         self._thread.start()
     81 
     82     def destroy(self):
     83         """ 停止并销毁自身 """
     84         process.stdout.close()
     85         self._thread.stop()
     86         del self
     87        
     88 
     89 
     90 
     91 
     92 
     93 if __name__ == '__main__':   #那么我们来开始使用它吧
     94     e = None
     95 
     96     #反馈函数
     97     def event(cls,line):#输出反馈函数
     98         sys.stdout.write(line)
     99 
    100     def exit(msg):#退出反馈函数
    101         print(msg)
    102 
    103     def ready():#线程就绪反馈函数
    104         e.write("dir")  #执行
    105         e.write("ping www.baidu.com")
    106         e.write("echo Hello!World 你好中国!你好世界!")
    107         e.write("exit")
    108 
    109     e = SwPipe("cmd.exe",event,exit,ready)
    110     e.start()

    输出:

     

     你可以看见,我们的指令都顺序的执行了。当然了这里面还有OS的功劳。

    那么你的可扩展的Pipe类应该已经构建完毕了吧?

    A: 我之所以要在这种代码前面加入行数的原因就是为了防止你复制;因为你可能永远不会明白这里究竟发生了什么,而是只懂得了使用。

    顺便一提:

    最好去参考一下官方的文档,已经讲得非常详细了。subprocess.Popen.communicate 或许更适合你,看你是要进行什么事情。

    参考:

    https://docs.python.org/3/library/subprocess.html

    到此结束,如有错误之处还望指正。

    不论是否对你有帮助,感谢你耐心阅读

  • 相关阅读:
    BZOJ1999或洛谷1099&BZOJ2282或洛谷2491 树网的核&[SDOI2011]消防
    BZOJ1912或洛谷3629 [APIO2010]巡逻
    CH6202 黑暗城堡
    POJ2728 Desert King
    JoyOI1391 走廊泼水节
    洛谷1073 最优贸易
    POJ3662或洛谷1948 Telephone Lines
    BZOJ1106 [POI2007]立方体大作战tet
    ubuntu 16.04 安装genymotion
    ubuntu下搭建android开发环境核心篇安装AndroidStudio、sdk、jdk
  • 原文地址:https://www.cnblogs.com/suwings/p/6216279.html
Copyright © 2020-2023  润新知