专栏首页lulianqi调用CMD命令的一个.NET工具类(MyWindowsCmd)

调用CMD命令的一个.NET工具类(MyWindowsCmd)

功能大概描述一下如果直接StandardOutput.ReadToEnd()这种方法,有很多限制

这类方式必须把命令全部执行一次写入并标记为exit,而且返回内容的获取会一直等待,如果在主线程里使用会导致假死。

若遇到执行时间长,同时会在执行中输出进度的命令,则明显不适应

对于部分特殊字符这类方法会直接中断一直等待(特别是对包含asc颜色等样式的输出)

本文的工具类解决以上问题,使用委托订阅的方式即时的输出执行过程,不用等待,异步输出结算后自动退出

方便应对类似这种需要长时间运行即时输出的打包命令。

下面直接贴出代码,方便后面的朋友 直接使用。

前一个类StreamAsynRead是用于读取cmd进程返回流IO 后面的MyWindowsCmd为cmd主要功能

  1 using System;
  2 using System.Collections.Generic;
  3 using System.Linq;
  4 using System.Text;
  5 
  6 using System.IO;
  7 using System.Threading;
  8 
  9 /*******************************************************************************
 10 * Copyright (c) 2016 lulianqi
 11 * All rights reserved.
 12 * 
 13 * 文件名称: 
 14 * 内容摘要: mycllq@hotmail.com
 15 * 
 16 * 历史记录:
 17 * 日      期:   201601212          创建人: lulianqi mycllq@hotmail.com
 18 * 描    述: 创建
 19 *******************************************************************************/
 20 
 21 namespace yourNamespaceName
 22 {
 23     class StreamAsynRead:IDisposable
 24     {
 25         public delegate void delegateGetStreamAsynReadEventHandler(object sender, string outData);
 26         public event delegateGetStreamAsynReadEventHandler OnGetAsynReadData;
 27 
 28         private Stream baseStream;
 29         private Thread readStreamThread;
 30         private Encoding baseEncode;
 31         private bool isDropAscStyle;
 32         private bool willKill;
 33 
 34         /// <summary>
 35         /// 异步读取指定IO流并即时返回直到该流结束(初始化完成后即开始读取)
 36         /// </summary>
 37         /// <param name="yourBaseStream">目标IO流</param>
 38         /// <param name="yourEncode">编码方式</param>
 39         /// <param name="dropAscStyle">是否丢弃ASC样式</param>
 40         /// <param name="yourGetAsynReadData">数据返回委托</param>
 41         public StreamAsynRead(Stream yourBaseStream, Encoding yourEncode, bool dropAscStyle , delegateGetStreamAsynReadEventHandler yourGetAsynReadData)
 42         {
 43             if (yourBaseStream == null)
 44             {
 45                 throw new Exception("yourBaseStream is null");
 46             }
 47             else
 48             {
 49                 isDropAscStyle = dropAscStyle;
 50                 baseStream = yourBaseStream;
 51                 baseEncode = yourEncode;
 52                 OnGetAsynReadData += yourGetAsynReadData;
 53                 StartRead();
 54                 willKill = false;
 55             }
 56         }
 57 
 58         public StreamAsynRead(Stream yourBaseStream, Encoding yourEncode, delegateGetStreamAsynReadEventHandler yourGetAsynReadData)
 59             : this(yourBaseStream, yourEncode, false, yourGetAsynReadData){}
 60 
 61         public StreamAsynRead(Stream yourBaseStream, delegateGetStreamAsynReadEventHandler yourGetAsynReadData)
 62             : this(yourBaseStream, ASCIIEncoding.UTF8, false, yourGetAsynReadData) { }
 63 
 64         public bool IsdropAscStyle
 65         {
 66             get { return isDropAscStyle; }
 67             set { isDropAscStyle = value; }
 68         }
 69 
 70 
 71         private void PutOutData(string yourData)
 72         {
 73             if(OnGetAsynReadData!=null)
 74             {
 75                 this.OnGetAsynReadData(this, yourData);
 76             }
 77         }
 78 
 79         private bool StartRead()
 80         {
 81             if(baseStream==null)
 82             {
 83                 return false;
 84             }
 85             if(readStreamThread!=null)
 86             {
 87                 if (readStreamThread.IsAlive)
 88                 {
 89                     readStreamThread.Abort();
 90                 }
 91             }
 92             readStreamThread = new Thread(new ParameterizedThreadStart(GetDataThread));
 93             readStreamThread.IsBackground = true;
 94             readStreamThread.Start(baseStream);
 95             return true;
 96         }
 97 
 98         private void GetDataThread(object ReceiveStream)
 99         {
100             /*
101             try
102             {
103             }
104             catch (ThreadAbortException abortException)
105             {
106                 Console.WriteLine((string)abortException.ExceptionState);
107             }
108              * */
109 
110             Byte[] read = new Byte[1024];
111             Stream receiveStream = (Stream)ReceiveStream;
112             int bytes = receiveStream.Read(read, 0, 1024);
113             string esc = baseEncode.GetString(new byte[] { 27, 91 });
114             //string bs = baseEncode.GetString(new byte[] { 8 });    //  \b
115             string re = "";
116             while (bytes > 0 && !willKill)
117             {
118                 re = baseEncode.GetString(read, 0, bytes);
119                 if (isDropAscStyle)
120                 {
121                     while (re.Contains(esc))
122                     {
123                         int starEsc = re.IndexOf(esc);
124                         int endEsc = re.IndexOf('m', starEsc);
125                         if (endEsc > 0)
126                         {
127                             re = re.Remove(starEsc, (endEsc - starEsc + 1));
128                         }
129                         else
130                         {
131                             re = re.Remove(starEsc, 2);
132                         }
133                     }
134                 }
135                 PutOutData(re);
136                 bytes = receiveStream.Read(read, 0, 1024);
137             }
138         }
139 
140         public void Dispose()
141         {
142             willKill = true;
143         }
144     }
145 
146     class MyWindowsCmd : IDisposable
147     {
148         public enum RedirectOutputType
149         {
150             RedirectStandardInput,
151             RedirectStandardError
152         }
153 
154         public delegate void delegateGetCmdMessageEventHandler(object sender, string InfoMessage, RedirectOutputType redirectOutputType);
155         /// <summary>
156         /// 订阅CMD返回数据
157         /// </summary>
158         public event delegateGetCmdMessageEventHandler OnGetCmdMessage;
159 
160         private System.Diagnostics.Process p = new System.Diagnostics.Process();
161         StreamAsynRead standardOutputRead = null;
162         StreamAsynRead standardErrorRead = null;
163         private string errorMes = null;
164         private string cmdName = null;
165         private bool isStart = false;
166         private bool isDropAscStyle = false;
167 
168         
169         public MyWindowsCmd()
170         {
171             p.StartInfo.FileName = "cmd.exe";
172             cmdName = "CMD";
173             p.StartInfo.UseShellExecute = false;    //是否使用操作系统shell启动
174             p.StartInfo.RedirectStandardInput = true;//接受来自调用程序的输入信息
175             p.StartInfo.RedirectStandardOutput = true;//由调用程序获取输出信息
176             p.StartInfo.RedirectStandardError = true;//重定向标准错误输出
177             p.StartInfo.CreateNoWindow = true;//不显示程序窗口
178             p.StartInfo.ErrorDialog = true;
179         }
180 
181         /// <summary>
182         /// 含名称字段的构造函数
183         /// </summary>
184         /// <param name="yourNmae">CMD名称(方便区分多份CMD实例)</param>
185         public MyWindowsCmd(string yourNmae):this()
186         {
187             cmdName = yourNmae;
188         }
189 
190         private void ShowMessage(string mes, RedirectOutputType redirectOutputType)
191         {
192             if (OnGetCmdMessage != null)
193             {
194                 this.OnGetCmdMessage(this, mes, redirectOutputType);
195             }
196         }
197 
198         /// <summary>
199         /// 获取CMD名称
200         /// </summary>
201         public string CmdName
202         {
203             get { return cmdName; }
204         }
205 
206         /// <summary>
207         /// 获取最近的错误
208         /// </summary>
209         public string ErrorMes
210         {
211             get { return errorMes; }
212         }
213 
214         /// <summary>
215         /// 获取一个值,盖值指示该CMD是否启动
216         /// </summary>
217         public bool IsStart
218         {
219             get { return isStart; }
220         }
221 
222         /// <summary>
223         /// 获取或设置获取内容回调时是否丢弃ASK颜色等样式方案(如果您的应用不具备处理这种样式的功能,请选择放弃该样式)
224         /// </summary>
225         public bool IsDropAscStyle
226         {
227             get { return isDropAscStyle; }
228             set { isDropAscStyle = value; }
229         }
230 
231         /// <summary>
232         /// 启动CMD
233         /// </summary>
234         /// <returns>是否成功启动</returns>
235         public bool StartCmd()
236         {
237             if(isStart)
238             {
239                 errorMes = "[StartCmd]" + "is Already Started";
240                 return false;
241             }
242             try
243             {
244                 p.Start();//启动程序
245                 //System.Text.Encoding.GetEncoding("gb1232");
246                 if (standardOutputRead!=null)
247                 {
248                     standardOutputRead.Dispose();
249                 }
250                 if (standardErrorRead!=null)
251                 {
252                     standardErrorRead.Dispose();
253                 }
254                 standardOutputRead = new StreamAsynRead(p.StandardOutput.BaseStream, System.Text.Encoding.Default, true, new StreamAsynRead.delegateGetStreamAsynReadEventHandler((obj, str) => { this.OnGetCmdMessage(this, str, RedirectOutputType.RedirectStandardInput); }));
255                 standardErrorRead = new StreamAsynRead(p.StandardError.BaseStream, System.Text.Encoding.Default, true, new StreamAsynRead.delegateGetStreamAsynReadEventHandler((obj, str) => { this.OnGetCmdMessage(this, str, RedirectOutputType.RedirectStandardError); }));
256                 isStart = true;
257                 return true;
258             }
259             catch (Exception ex)
260             {
261                 errorMes = "[StartCmd]" + ex.Message;
262                 return false;
263             }
264         }
265 
266         /// <summary>
267         /// 执行CMD命令
268         /// </summary>
269         /// <param name="yourCmd">cmd命令内容</param>
270         /// <returns>是否成功</returns>
271         public bool RunCmd(string yourCmd)
272         {
273             if(yourCmd==null || !isStart)
274             {
275                 return false;
276             }
277             try
278             {
279                 p.StandardInput.WriteLine(yourCmd);
280                 return true;
281             }
282             catch(Exception ex)
283             {
284                 errorMes = "[RunCmd]" + ex.Message;
285                 return false;
286             }
287         }
288 
289         /// <summary>
290         /// 等待执行完成(同步方法,请勿在主线程中调用)
291         /// </summary>
292         public void WaitForExit()
293         {
294             if (RunCmd("exit"))
295             {
296                 p.WaitForExit();
297             }
298         }
299 
300         /// <summary>
301         /// 停止该CMD,如果不准备再次启动,请直接调用Dispose
302         /// </summary>
303         public void StopCmd()
304         {
305             if(isStart)
306             {
307                 p.Close();
308                 isStart = false;
309             }
310         }
311 
312         public void Dispose()
313         {
314             StopCmd();
315             standardOutputRead.Dispose();
316             standardErrorRead.Dispose();
317         }
318     }
319 }

因为主要也是为了满足自己的需要,肯定还有很多错误或不合理的地方。

  发现任何错误或任何问题及建议,也感谢在下面留言

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 一个基于.NET平台的自动化/压力测试系统设计简述

    AutoTest是一个基于.NET平台实现的自动化/压力测试的系统,可独立运行于windows平台下,支持分布式部署,不需要其他配置或编译器的支持。(本质是一个...

    lulianqi
  • abstract virtaul override new 及多态

    abstract 修饰符可以和类、方法、属性、索引器及事件一起使用。在类声明中使用 abstract 修饰符以指示某个类只能是其他类的基类。标记为抽象或包含在抽...

    lulianqi
  • 借助FreeHttp为任意移动端web网页添加vConsole调试

    以下介绍在不用修改代码并发布项目的情况下,为我们日常使用的移动web应用(如手机web淘宝)添加vConsole调试工具的方法

    lulianqi
  • c# 获取电脑硬件信息通用查询类[测试通过]

    C#获取电脑硬件信息通用类[Computer]代码展示和分析,简介如下: 1.项目中添加System.Management引用。 2.添加类Computer,把...

    Java中文社群_老王
  • Excel模板导出之导出教材订购表

    本教程主要说明如果使用Magicodes.IE.Excel完成教材订购表的Excel模板导出。

    心莱科技雪雁
  • 再谈Newtonsoft.Json高级用法

      上一篇Newtonsoft.Json高级用法发布以后收到挺多回复的,本篇将分享几点挺有用的知识点和最近项目中用到的一个新点进行说明,做为对上篇文章的补充。 ...

    用户1168362
  • Magicodes.IE之Excel模板导出教材订购表

    本教程主要说明如果使用Magicodes.IE.Excel完成教材订购表的Excel模板导出。

    雪雁-心莱科技
  • 快速入门系列--WebAPI--04在老版本MVC4下的调整

    WebAPI是建立在MVC和WCF的基础上的,原来微软老是喜欢封装的很多,这次终于愿意将http编程模型的相关细节暴露给我们了。在之前的介绍中,基本上都基于.N...

    用户1216676
  • .NET框架设计(常被忽视的框架设计技巧)

    阅读目录: 1.开篇介绍 2.元数据缓存池模式(在运行时构造元数据缓存池) 2.1.元数据设计模式(抽象出对数据的描述数据) 2.2.借助Dynamic来改变...

    王清培
  • mvc自定义全局异常处理

      异常信息处理是任何网站必不可少的一个环节,怎么有效显示,记录,传递异常信息又成为重中之重的问题。本篇将基于上篇介绍的html2cancas截图功能,实现mv...

    用户1168362

扫码关注云+社区

领取腾讯云代金券