功能大概描述一下若是直接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