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)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • python安装jieba库的具体步骤_无法安装lxml库

    python安装jieba库的具体步骤_无法安装lxml库Jupternotebook安装jieba库教程jieba库是一款优秀的Python第三方中文分词库,jieba支持三种分词模式:精确模式、全模式和搜索引擎模式,下面是三种模式的特点。精确模式:试图将语句最精确的切分,不存在冗余数据,适合做文本分析 全模式:将语句中所有可能是词的词语都切分出来,速度很快,但是存在冗余数据 搜索引擎模式:在精确模式的基础上,对长词再次进行切分jieba库是第三方库,我们需要单独进行安装,以下提供两种方法:第一种方法:在jupyternoteboo

    2022年9月21日
    0
  • Okio基本使用以及源码分析

    Okio基本使用以及源码分析Okio是什么在OkHttp的源码中经常能看到Okio的身影,所以单独拿出来学习一下,作为OkHttp的低层IO库,Okio确实比传统的java输入输出流读写更加方便高效。Okio补充了java.io和java.nio的不足,使访问、存储和处理数据更加容易,它起初只是作为OKHttp的一个组件,现在你可以独立的使用它来解决一些IO问题。先看下okio库中类之间的关系:okio中最关键的是对于缓存队列的管理,这些优化操作使得okio在复制数据的时候可以减少拷贝次数,来看下okio中数据保存的数据结构是

    2022年5月27日
    37
  • linux中用户态和内核态是什么_用户态内核

    linux中用户态和内核态是什么_用户态内核内核态:操作系统在内核态运行——运行操作系统程序用户态:应用程序只能在用户态运行——运行用户程序当一个进程在执行用户自己的代码时处于用户运行态(用户态),此时特权级最低,为3级,是普通的用户进程运行的特权级,大部分用户直接面对的程序都是运行在用户态。Ring3状态不能访问Ring0的地址空间,包括代码和数据;当一个进程因为系统调用陷入内核代码中执行时处于内核运行态(内核态),此时特权级最高,为0级。执行的内核代码会使用当前进程的内核栈,每个进程都有自己的内核栈。…

    2022年9月17日
    0
  • 马哥学习—-李洋个人笔记–启动故障排除

    马哥学习—-李洋个人笔记–启动故障排除故障1删除/boot之后的恢复步骤:1重启电源,迅速按esc进去选择启动模式,然后选cd-rom这项(从光驱启动)2重启后进入救援模式(选择rescue),选择语言和键盘布局后,一路回车到下一步。3询问是否需要网络选项,一般来说,救援模式不需要网络,选择no,回车进入下一步。4这一步提示内容大意为:救援系统将尝试寻找你的linux安装,并在目录mnt/sysimage下安装它…

    2022年7月21日
    12
  • ExecutorService详解[通俗易懂]

    ExecutorService详解[通俗易懂]前言    在我们的日常开发中,难免会使用到线程,部分还会用到多线程并发问题。我们知道,线程的创建和释放,需要占用不小的内存和资源。如果每次需要使用线程时,都new一个Thread的话,难免会造成资源的浪费,而且可以无限制创建,之间相互竞争,会导致过多占用系统资源导致系统瘫痪。不利于扩展,比如如定时执行、定期执行、线程中断,所以很有必要了解下ExecutorService的使用。…

    2022年9月11日
    0
  • lombok几个基本注解的使用@Data@AllArgsConstructor@NoArgsConstructor@Builder

    lombok几个基本注解的使用@Data@AllArgsConstructor@NoArgsConstructor@Builderlombok是一款在java开发中简洁化代码十分有用的插件工具,这篇博客对较为常用的几种注解进行记录,分享学习心得。使用lombok注解,目的和作用就在于不用再去写经常反复去写的(如Getter,Setter,Constructor等)一些代码了。首先,用到的几个注解:@Data使用这个注解,就不用再去手写Getter,Setter,equals,canEqual,hasCode,toS…

    2022年10月18日
    0

发表回复

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

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