功能大概描述一下如果直接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 * 内容摘要: [email protected] 15 * 16 * 历史记录: 17 * 日 期: 201601212 创建人: lulianqi [email protected] 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 }
因为主要也是为了满足自己的需要,肯定还有很多错误或不合理的地方。
发现任何错误或任何问题及建议,也感谢在下面留言
时间: 2024-10-12 09:04:52