zoukankan      html  css  js  c++  java
  • 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

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

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

  • 相关阅读:
    POJ 1469 COURSES 二分图最大匹配
    POJ 1325 Machine Schedule 二分图最大匹配
    USACO Humble Numbers DP?
    SGU 194 Reactor Cooling 带容量上下限制的网络流
    POJ 3084 Panic Room 求最小割
    ZOJ 2587 Unique Attack 判断最小割是否唯一
    Poj 1815 Friendship 枚举+求最小割
    POJ 3308 Paratroopers 最小点权覆盖 求最小割
    1227. Rally Championship
    Etaoin Shrdlu
  • 原文地址:https://www.cnblogs.com/suwings/p/6216279.html
Copyright © 2011-2022 走看看