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

 

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

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

赞 (0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 架构设计&分布式&数据结构与算法面试题(2020最新版)「建议收藏」

    架构设计&分布式&数据结构与算法面试题(2020最新版)「建议收藏」文章目录架构设计请列举出在JDK中几个常用的设计模式?什么是设计模式?你是否在你的代码里面使用过任何设计模式?静态代理、JDK动态代理以及CGLIB动态代理静态代理动态代理cglib代理单例模式工厂模式观察者模式装饰器模式秒杀系统设计分布式分布式概述分布式集群微服务多线程高并发分布式系统设计理念分布式系统的目标与要素分布式系统设计两大思路:中心化和去中心化分布式与集群的区别是什么?CAP定理CAP…

    2022年5月31日
  • 一些好玩的cmd命令_好玩cmd命令

    一些好玩的cmd命令_好玩cmd命令前言:CMD是什么?在windows环境下,命令行程序为cmd.exe。是一个32位的命令行程序,微软Windows系统基于Windows上的命令解释程序。类似于微软的DOS操作系统。输入一些命令,cmd.exe可以执行。比如输入shutdown-s就会在30秒后关机。总之,它非常有用。很多朋友往往都对黑客比较崇拜,其实黑客也只是比我们知道更多一些我们所不了解的电脑相关命令。在使用中…

    2022年9月22日
  • The method assertEquals(double, double) from the type Assert is deprecated

    The method assertEquals(double, double) from the type Assert is deprecated从网上下载的视频,看着视频做。居然和人家的不一样。assertEquals(doubleexpected,doubleactul)被废弃了,换成assertEquals(doubleexpected,doubleactul,doubledelta)也就是在原来的方法上加一个误差值(double类型)官方解释为:@Deprecatedstaticpublicvoi

    2022年7月12日
  • vue(21)初识Vuex[通俗易懂]

    vue(21)初识Vuex[通俗易懂]Vuex是做什么的?官方解释:Vuex是一个专为Vue.js应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。Vuex

    2022年7月30日
  • oracle到hive数据类型转换「建议收藏」

    oracle到hive数据类型转换「建议收藏」oracle和hive中的数据类型存在差异,在oracle集成数据到hive中这样的场景下,我们希望在hive中的数据是贴源的,所以在hive中希望创建和oracle结构一致的表。oracle到hive数据类型映射参考如下:selectcasewhent1.column_id=1then’CREATETABLEIFNOTEXISTS’||’project’||’….

    2022年9月21日
  • IDEA 非maven项目打jar包(包含第三方依赖包)

    IDEA 非maven项目打jar包(包含第三方依赖包)**IDEA非maven项目打jar包**普通java项目打JAR包方式(包含第三方依赖包):①在保证程序能运行情况下:②③④***最后就生成JAR包了在相应文件夹下运行控制台命令java-jar.jar就可以运行了…

    2022年6月19日

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

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