調用CMD命令的一個.NET工具類(MyWindowsCmd)

功能大概描述一下若是直接StandardOutput.ReadToEnd()這種方法,有不少限制shell

這類方式必須把命令所有執行一次寫入並標記爲exit,並且返回內容的獲取會一直等待,若是在主線程裏使用會致使假死。異步

若遇到執行時間長,同時會在執行中輸出進度的命令,則明顯不適應函數

對於部分特殊字符這類方法會直接中斷一直等待(特別是對包含asc顏色等樣式的輸出)工具

本文的工具類解決以上問題,使用委託訂閱的方式即時的輸出執行過程,不用等待,異步輸出結算後自動退出this

 

方便應對相似這種須要長時間運行即時輸出的打包命令。編碼

 

 

下面直接貼出代碼,方便後面的朋友 直接使用。spa

前一個類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 }

  由於主要也是爲了知足本身的須要,確定還有不少錯誤或不合理的地方。線程

  發現任何錯誤或任何問題及建議,也感謝在下面留言code

相關文章
相關標籤/搜索