经常看到论坛中有人问到当用Process组件启动新的进程后,如何获取它的输出的问题。采取将子进程的输出定向到一个临时文件中,当然也可以解决问题。但是这样每次父进程从临时文件中获取信息后,还要删除该临时文件,毕竟比较麻烦。其实,Process提供了几个属性可以获取输出。在.net框架sdk的帮助文档里面就有这方面的例子,但是对于如何同时获取错误输出和标准输出方面没有给出具体代码,本文将给出实例并对管道的特性作一些说明。
一、获取子进程标准输出和错误输出的的方法:
我们写一个小程序p2.cs,用它来产生标准输出和错误输出。
//p2.cs代码如下:
using System;
class class1
{
public static void Main()
{
int i = 0;
string s1 = String.Format("out:{0,4}--------------------------------------------------",i);
System.Console.Out.WriteLine(s1);
string s2 = String.Format("err:{0,4}**************************************************",i);
System.Console.Error.WriteLine(s2);
}
}
编译成p2.exe
获取子进程的标准输出和错误输出的源程序
//p1.cs
....
Process p = new Process("p2.exe");
p.StartInfo.UseShellExecute = false; //指定不使用系统的外壳程序,而是直接启动被调用程序本身
p.StartInfo.RedirectStandardOutput = true; //只有将此属性设为true,才能通过管道获取子进程输出
p.StartInfo.RedirectStandardError = true;
p.Start();//启动子进程
string output = p.StandardOutput.ReadToEnd(); //读取标准输出
string error = p.StandardError.ReadToEnd();//读取错误输出
p.WaitForExit();//等待子进程执行完毕
...
上例中,父进程启动子进程后,就等待着从管道中取走标准输出,取走全部标准输出后取走错误输出。我们运行起来没有任何错误。但是一旦我门增加p2.exe中的标准输出和错误输出的字节数:
for(i=0;i<200;i++)
System.Console.Out.WriteLine(s1);
for(i=0;i<200;i++)
System.Console.Error.WriteLine(s2);
编译后,再运行,就会发现父进程和子进程出现了死锁,只有强行关闭才能终止进程。
二、管道:
Process 组件通过管道与子进程进行通讯。如果同时重定向标准输出和标准错误,然后试图读取它们,当管道被填满时候就会出现问题。上例中,父进程只有读完了所有的标准输出才能读错误输出,而子进程的标准输出每当把管道填满时候,父进程都会取走,子进程接着向管道输出后续的标准输出。这都运行的很好。可是当子进程执行到输出错误输出的时候,由于子进程还没有运行结束,它的标准输出流就不会处于结束状态(虽然在我们的例子中它的200次循环的标准输出已经执行完毕),这就导致父进程中的ReadToEnd()方法不会执行完毕,所以父进程中的p.StandardError.ReadToEnd()无法执行,从而管道中的错误输出无法被读取,子进程的后续错误输出无法写入管道,最终子进程和父进程彼此无限等待,出现了阻塞情况。
子进程通过检查管道中最后一个字节是否被取走,来决定是否输出后续内容。也就是说,如果管道缓冲区中最后一个字节之前的所有内容都被取走,子进程仍然会处于等待中;如果前面所有字节都没有取走,但最后一个字节内容被取走,子进程会继续向管道里输出后续内容,当然这样只能输出一字节到管道中最后位置。
我们如果把p1.cs中的string output = p.StandardOutput.ReadToEnd()改为:
for(int i=0;i<200*60;i++)
Console.Write((char) p.StandardOutput.Read());
就不会出现死锁情况。因为当获取标准输出的循环执行完后,会接着执行获取错误输出的语句,而不需等待标准输出流的结束。但是这种方法毫无实际意义,因为实际中,我们并不可能像本例中知道标准输出会有多少字节。
三、用多线程分别获取标准输出和错误输出
对于这种情况,.net框架文档中建议这样解决:创建两个线程,以便应用程序可以在单独的线程上读取每个流的输出。下面给出例子:
//p1.cs:
...
class class1
{
.....
public static void Main()
{
ProcessStartInfo pi = new ProcessStartInfo();
pi.FileName = @"c:\p2.exe";
pi.UseShellExecute = false;
pi.RedirectStandardOutput = true;
pi.RedirectStandardError = true;
System.Diagnostics.Process p = new Process();
p.StartInfo = pi;
p.Start();
tout t1 = new tout(p);
terr t2 = new terr(p);
Thread thread1 = new Thread(new ThreadStart(t1.Read));
Thread thread2 = new Thread(new ThreadStart(t2.Read));
thread1.Start();
thread2.Start();
p.WaitForExit();
Console.WriteLine("p2.exe结束");
}
}
class tout
{
Process p;
public tout(Process p)
{
this.p = p;
}
public void Read()
{
int a = -1;
while((a = p.StandardOutput.Read()) > 0)
{
Console.Write( ((char) a).ToString() );
}
Thread.CurrentThread.Abort();
return;
}
}
class terr
{
Process p;
public terr(Process p)
{
this.p = p;
}
public void Read()
{
int a = -1;
while((a = p.StandardError.Read()) > 0)
{
Console.Write(((char) a).ToString());
}
Thread.CurrentThread.Abort();
return;
}
}
分享到:
相关推荐
首先是获取特定进程对象,可以使用Process.GetProcesses()方法来获取系统中运行...首先是获取本机中所有进程对象,分别输出某一时刻各个进程的内存使用情况: using System; using System.Collections.Generic; using
获取系统当前活跃进程,输出进程信息以及进程加载dll信息。
写了个类,用以调用其他exe,可以以同步或异步方式调用,可以设置超时时长,exe运行中产生的输出信息也可捕获到。 见:http://blog.csdn.net/beanjoy/article/details/9167767
启动EXE进程获取输出信息
这个例子是使用NT式驱动获取系统正在运行的进程,需要使用Dbgview捕获驱动程序的输出内容
为了方便使用,实现了两个帮助类来方便的获取进程的输出,分别是 ProcessExecutor 和 CommandRunner,前者更为灵活,可以通过事件添加自己的额外事件订阅处理,后者为简化版,主要是只获取输出的场景,两者的实现...
/u [<Domain>\]<UserName> 指定使用哪个用户执行这个命令。 /P [password] 为指定的用户指定密码。 /M [module] 列出调用指定的DLL模块的所有进程。如果没有指定模块名,显示每个进程加载的所有模块。 /SVC 显示...
Java获取系统信息(cpu,内存,硬盘,进程等)的相关方法.pdf
Process启动进程完成交互并获取输出例程。 详情看博客:https://xiaolong.blog.csdn.net/article/details/119177349
4.根据关键字获取进程号 5.根据关键字获取进程数量 6.当进程数量是0的时候调用重启脚本重启进程 7.写数据库函数发短信 8.输出监控结果 调用方法: 监控weblogic,若发现异常则重启进程,并发送短信(入库) sh $...
今天小编就为大家分享一篇Python 从subprocess运行的子进程中实时获取输出的例子,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
操作系统实验,压缩包中包括Linux和windows进程控制源代码及实验报告。 进程控制实验题目: 设计并实现Unix的“time”命令。“mytime”命令通过命令行参数接受要运行的程序,创建一个独立的进程来运行该程序,并...
此代码示范了如何获取某个进程的主窗口以及创建此进程的程序名(19kb)
python代码可设置查询条件,设置多进程获取网易云课堂课程信息,并保存到MySQL数据库中,方便后续查询使用。 pool = Pool() # 开启进程 index = ([x for x in range(1,totlePageCount+1)]) # ...') # 输出执行时间
源代码这是一个头文件,解决了命令行输入输出重定向问题,可以直接使用。测试代码如下: #include "console.h" #include using namespace std; int _tmain(int argc, _TCHAR* argv[]) { Console console; if( ...
父进程定时、随机产生一个由 12 个字符组成的字符串,子进程获取此字符 串后将字符串反转后输出并通知父进程。要求程序在运行过程种屏蔽 “Ctrl+C”,仅当程序接收到键盘输入“q”或“Q”时退出。
使用wmi4j 连接远程主机获取进程列表,创建文件夹、共享文件夹、执行netstat -ano输出到aa.txt文件,读取文件、撤销文件夹共享、删除文件夹及aa.txt文件;即实现远程执行cmd命令获取命令执行的结果的效果。
所以我就在想,我今后启动这个脚本时,进行检查,如果上次运行的脚本还没结束,而且过了某个时间阀值,就把它及其子进程给kill掉。然后,我就需要写了一个可以查询某个进程已经运行了多少时间(以second为单位)的...
在windows 环境下编写一个控制台应用程序,输出系统中正在运行的进程的信息,包括进程号、进程所运行的程序、进程的启动时间、在核心态下消耗的时间以及在用户态下消耗的时间。 3。在windows 环境下编写一个控制台...