Loading

调用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 }

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

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

posted @ 2016-12-16 13:45  lulianqi15  阅读(1797)  评论(11编辑  收藏  举报