功能大概描述一下如果直接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 }
因为主要也是为了满足自己的需要,肯定还有很多错误或不合理的地方。
发现任何错误或任何问题及建议,也感谢在下面留言