C#Cmd实时输出同步交互不会堵塞

发布于:2024-06-12 ⋅ 阅读:(180) ⋅ 点赞:(0)

调用cmd只能用流数据实时获取输出内容,同步输入输出不及时处理一样会堵塞,但你可以改动代码采用异步的方式,下面的实现方式和socket的方法一样,其他语言也是一样的思路。

 public class ApiCmd
 {
     public int time=100;//随时设置等待时间
     public ApiCmd(int _time=100) { time = _time; }
     public const int ReadSize = 2048;//缓冲区大小
     private Encoding encoding;//字符编码
     private Process cmd;//cmd进程
     public event Action Exited;//退出事件
     public event Action<string, StreamWriter> output;//输出事件
     private byte[] ReadBuffer = new byte[ReadSize];//缓冲区
     private List<byte> ReadList = new List<byte>();//暂存区
     public void Start()
     {
         cmd = new Process();
         cmd.StartInfo.FileName = "cmd.exe";
         cmd.StartInfo.UseShellExecute = false;//是否使用操作系统shell启动
         cmd.StartInfo.RedirectStandardInput = true;//接受来自调用程序的输入信息
         cmd.StartInfo.RedirectStandardOutput = true;//由调用程序获取输出信息
         cmd.StartInfo.RedirectStandardError = true;//重定向标准错误输出
         cmd.StartInfo.CreateNoWindow = true;//不显示程序窗口
         cmd.Exited += Process_Exited;
         cmd.Start();
         encoding = cmd.StandardOutput.CurrentEncoding;
         cmd.StandardOutput.BaseStream.BeginRead(ReadBuffer, 0, ReadSize, ReadCallback, null);
         cmd.StandardError.BaseStream.BeginRead(ReadBuffer, 0, ReadSize, ErrorCallback, null);
         cmd.StandardInput.AutoFlush = true;
         cmd.StandardInput.WriteLine("echo Hello World!");
     }
     private bool IsRun = false;
     private void ErrorCallback(IAsyncResult ar)
     {
         int count = cmd.StandardError.BaseStream.EndRead(ar);
         if (count < 1) { if (cmd.HasExited) { cmd.Close(); } return; }
         else
         {
             byte[] temp = new byte[count];
             Buffer.BlockCopy(ReadBuffer, 0, temp, 0, temp.Length);
             ReadList.AddRange(temp);
             if (!IsRun) {IsRun = true; Thread thread = new Thread(delegate () { ThreadCallback(ReadList); }); thread.IsBackground = false; thread.Start(); }
             cmd.StandardError.BaseStream.BeginRead(ReadBuffer, 0, ReadSize, ErrorCallback, null);
         }
     }
     private void ThreadCallback(List<byte> readt)
     {
         int count = readt.Count;
         Thread.Sleep(time);//等待
         if (ReadList.Count > count) { Thread thread = new Thread(delegate () { ThreadCallback(ReadList); }); thread.IsBackground = false; thread.Start();return; }/*等待期过后如果数组变更则重新等待*/
         else 
         {
             IsRun = false;
             output.Invoke(encoding.GetString(ReadList.ToArray()), cmd.StandardInput);ReadList.Clear();
         }
     }
     private void ReadCallback(IAsyncResult ar)
     {
         int count = cmd.StandardOutput.BaseStream.EndRead(ar);
         if (count < 1) { if (cmd.HasExited) { cmd.Close(); } return; }
         else
         {
             byte[] temp = new byte[count];
             Array.Copy(ReadBuffer, 0, temp, 0, temp.Length);
             ReadList.AddRange(temp);
             if (!IsRun) { IsRun = true; Thread thread = new Thread(delegate () { ThreadCallback(ReadList); }); thread.IsBackground = false; thread.Start(); }
             cmd.StandardOutput.BaseStream.BeginRead(ReadBuffer, 0, ReadSize, ReadCallback, null);
         }
     }
     private void Process_Exited(object sender, EventArgs e) { Exited.Invoke(); }

        public void WriteLine(string str) { cmd.StandardInput.WriteLine (str); }
     public void Close() { cmd.Dispose(); cmd.Close(); }
 }

/**************************调用方式******************************/

  List<string> output = new List<string>();

output.Add("keytool -genkey -alias myae -keyalg RSA -keystore mykeystore.jks");
            output.Add("123456");
            output.Add("1");
            output.Add("2");
            output.Add("3");
            output.Add("4");
            output.Add("5");
            output.Add("6");
            output.Add("是");
            output.Add("123456");
            output.Add("123456");
            ApiCmd cmd = new ApiCmd(500);//等待时间500毫秒
            cmd.output += Cmd_output1;//命令输出
            cmd.Start();

        private void Cmd_output1(string arg1, StreamWriter arg2)
        {
            if (output.Count > 0) {
                arg2.WriteLine(output[0]);output.RemoveAt(0);
            }

//arg1是一条完整的信息,但等待数据设置太低可能无法获取完整的信息甚至报错
        }