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

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

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

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”这个查看设备列表的指令。

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

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

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • [计算机网络]交换机VLAN的作用和原理

    [计算机网络]交换机VLAN的作用和原理本节将讨论什么是交换机VLAN产生的原因,以及如何起作用的

  • 可迭代对象 python_列表是可迭代对象吗

    可迭代对象 python_列表是可迭代对象吗引出问题:​如下面所示,存在一个类,并且产生了一个对象,现在想用for循环实现对象的迭代,结果报错了点击(此处)折叠或打开– coding: utf-8 –“””演示一个类是不可以迭代的结果存在报错信息 说明 A对象不是一个可以迭代的对象for i in A:TypeError: ‘Students’ object is not iterable“””class Students():def init(self):self.names = list()def add(self,

  • iphone上的设备管理去哪里了_iPhone设备管理在哪里找

    iphone上的设备管理去哪里了_iPhone设备管理在哪里找正常是没有设备管理的选项的,当你的iPhone上有未信任程序(已经安装好的才行,正在下载/安装的都不算)时才会有这个选项设置>通用>设备管理

  • mt4 python_一个使用Python自动化交易外汇MT4脚本实现「建议收藏」

    mt4 python_一个使用Python自动化交易外汇MT4脚本实现「建议收藏」安装C++运行环境[需要C++的运行环境,TheDLLsrequirethatyouhavethelatestVisualC++runtime(2015)]:https://support.microsoft.com/en-us/help/2977003/the-latest-supported-visual-c-downloads克隆代码下来关闭杀毒软件!!!解压MT4配置…

  • pycharm使用技巧及常用快捷键_常用快捷键大全图片

    pycharm使用技巧及常用快捷键_常用快捷键大全图片Pycharm常用快捷键1、编辑(Editing)Ctrl+Space基本的代码完成(类、方法、属性)Ctrl+Alt+Space快速导入任意类Ctrl+Shift+Enter语句完成Ctrl+P参数信息(在方法中调用参数)Ctrl+Q快速查看文档F1外部文档Shift+F1外部文档,进入web文档主页Ctrl+Shift+Z–>Redo重做Ctrl+鼠标简介/进入代码定义Ctrl+F1显示错误描述或警告.

  • ipv6修改DNS服务-首选DNS服务器:240c::6666「建议收藏」

    ipv6修改DNS服务-首选DNS服务器:240c::6666「建议收藏」下一代互联网国家工程中心推出的IPv6DNS服务首选DNS服务器:240c::6666备用DNS服务器:240c::6644来自下一代互联网国家工程中心官网消息显示,日前,下一代互联网国家工程中心正式宣布推出IPv6公共DNS:240c::6666。通过免费提供性能优异的公共DNS服务,为广大IPv6互联网用户打造安全、稳定、高速、智能的上网体验,助力我国…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号