前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >winfrom – 重定向控制台的输入输出

winfrom – 重定向控制台的输入输出

作者头像
全栈程序员站长
发布2022-07-05 08:38:15
1.2K0
发布2022-07-05 08:38:15
举报
文章被收录于专栏:全栈程序员必看

windows 系统控制台里给我提供很方便的运行的程序的方式。类似老式的dos环境。但是这种控制台的交互风格还是非常方便的。即便在现在的情况下,因为有些操作不使用图形化的界面反而会比较快捷。在控制台环境下,我们可以执行很多指令,比如“dir”,”ipconfig /all”,”ping”等。我们今天尝试做个图形化的界面,同样可以执行执行,并将执行的结果在winform窗体里显示。如下图:

winfrom - 重定向控制台的输入输出
winfrom - 重定向控制台的输入输出

如上图所示,该窗体类似打开了一个控制台,在下方的文本框输入 “dir”指令时,会在上面提示区显示执行后的结果的内容。

这个过程是怎么实现的呢?实际上开启了一个控制台的进程,在这个进程里执行了cmd(相当于你启动一个控制台)。在我们的程序执行时,我们将 指令(比如上面输入的dir指令)发送给 这个进程,并且将这个进程的输出结果读取出来,显示在我们的winform窗体界面上。也就是说,我们开启了一个控制台,并为这个控制台做了输入,输出的重新定向,将这个控制台的输入输出的通道指向了我们的应用程序。使得我们可以将指令通过这个通道发送给控制台,并读取到控制台的输出结果。

我们是如何启动一个控制台的进程呢?代码如下:

ProcessStartInfo startInfo = new ProcessStartInfo(); startInfo.FileName = “ cmd “ ; startInfo.CreateNoWindow = true ; startInfo.UseShellExecute = false ; // startInfo.WindowStyle = ProcessWindowStyle.Normal; startInfo.RedirectStandardInput = true ; startInfo.RedirectStandardOutput = true ; startInfo.RedirectStandardError = true ; startInfo.WorkingDirectory = Application.StartupPath;

_consoleProcess = Process.Start(startInfo);

在这里 构建了一个ProcessStartInfo 对象,这个对象描述了一个 启动项信息,它包括了 文件名,参数等。再调用Process.Start(startInfo)方法,来启动它。

注意上面的代码中,我们开启了它的重定向,也就是这三行代码:

startInfo.RedirectStandardInput = true ; startInfo.RedirectStandardOutput = true ; startInfo.RedirectStandardError = true ;

它指示了我们会对这个进程的输入,输出,错误进行重定向。

那么在,启动了一个重定向后的进程后,我们如何读取输出的内容,错误信息,和输入数据呢?

ThreadPool.QueueUserWorkItem( new WaitCallback( delegate { while ( true ) { if (_consoleProcess != null && ! _consoleProcess.HasExited) { StreamReader sr = _consoleProcess.StandardError; string str = sr.ReadLine(); Println(str);

} Thread.Sleep( 10 ); } }));

ThreadPool.QueueUserWorkItem( new WaitCallback( delegate { while ( true ) { if (_consoleProcess != null && ! _consoleProcess.HasExited) { StreamReader sr = _consoleProcess.StandardOutput; string str = sr.ReadLine(); Println(str); } Thread.Sleep( 10 );

} }));

如上面的代码所示,我么启动了两个线程,在这两个线程里,我们不停的读取这个进程 的 输出流,和错误流 里的数据,如果有,我们就把它显示出来。

那么如何写入数据到这个进程的输入流呢?

string command = txtCommand.Text.Trim(); if ( ! string .IsNullOrEmpty(command)) { if (_consoleProcess != null && ! _consoleProcess.HasExited) { StreamWriter sw = _consoleProcess.StandardInput; sw.WriteLine(command); }

Println(command);

txtCommand.Text = “” ; }

如上代码所示,我们从一个TextBox里(名字是txtCommand)读取 用户在窗体的输入框里输入的内容,然后获得 这个流的StandardInput,并将数据写过这个流内。

同时显示获得的数据内容的方法Println的实现:

/// <summary> /// 输出 /// </summary> /// <param name=”str”></param> public void Println( string str) { this .Invoke( new MethodInvoker( delegate { if (str.EndsWith( “ \n “ )) { txtMessage.AppendText(str); } else { txtMessage.AppendText(str + “ \n “ ); } txtMessage.ScrollToCaret(); })); }

至此,我们就完成了一个控制台的重定向演示。

代码下载

—-

下面是一些扩展内容

有时候我们会拿到一些exe文件,这些文件运行在控制台模式,必须sqlite,android里的adb等。这个时候我们需要调用这些exe来执行一些操作,而且想获得这些操作的执行结果,于是,我尝试自己封装了一个类,该类用于执行 这样的exe,并获得执行结果。代码如下:

/* ———————————————————- * @名称 : * @描述 : * @创建人 : 张云飞 * @创建日期: 2011/7/8 15:10:14 * @修改记录: * ———————————————————- */

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Diagnostics;

namespace WinApp_RunConsoleDemo { /// <summary> /// 指令 /// </summary> public class Command { string _workDirectory;//工作文件夹,应该指向 你要执行的exe文件的所在路径

public Command() {

}

public Command( string workDirectory) { _workDirectory = workDirectory; } //comamndString是要执行的文件名,argment是执行参数,output是执行的输出结果,errout是当错误时返回的结果。

//返回值是 是否成功执行,如果失败了,就查看下errout内的信息 public bool RunCommand( string comamndString, string argment, out string output, out string errout) { StringBuilder _result = null ; StringBuilder _error = null ;

_result = new StringBuilder(); _error = new StringBuilder();

ProcessStartInfo startInfo = new ProcessStartInfo(); startInfo.FileName = comamndString; // “adb devices”; startInfo.Arguments = argment; startInfo.CreateNoWindow = true ; startInfo.UseShellExecute = false ; // startInfo.WindowStyle = ProcessWindowStyle.Normal; startInfo.RedirectStandardInput = true ; startInfo.RedirectStandardOutput = true ; startInfo.RedirectStandardError = true ; startInfo.WorkingDirectory = _workDirectory;

Process process1 = null ; try { process1 = Process.Start(startInfo);

// 接收错误的事件 process1.ErrorDataReceived += ( object sender, DataReceivedEventArgs e) => { if ( ! string .IsNullOrEmpty(e.Data)) { _result.AppendLine(e.Data); } }; // 接收数据的事件 process1.OutputDataReceived += ( object sender, DataReceivedEventArgs e) => { if ( ! string .IsNullOrEmpty(e.Data)) { _error.AppendLine(e.Data); } }; process1.BeginErrorReadLine(); process1.BeginOutputReadLine();

// result = sr2.ReadToEnd(); // err = sr1.ReadToEnd(); process1.WaitForExit(); } catch (Exception) { throw ; } finally { if (process1 != null && ! process1.HasExited) { process1.Kill(); } }

output = _result.ToString(); errout = _error.ToString();

_error = null ; _result = null ;

if ( ! string .IsNullOrEmpty(errout)) { return false ; } else { return true ; } } }

}

下面是执行的测试代码:

Command cmd = new Command(Application.StartupPath);

string output; string error; if (cmd.RunCommand( “ adb.exe “ , “ devices “ , out output, out error)) {

MessageBox.Show( “ Ok: “ + output); } else { MessageBox.Show( “ Error: “ + error); }

如上代码所示,我指向了一个路径“Application.StartupPath”,这个是应用程序的启动目录,我在这里将android的adb.exe拷贝到了应用程序的根目录。上面代码相当于执行了”adb devices”这个查看设备列表的指令。

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/110596.html原文链接:https://javaforall.cn

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021年8月1,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档