C#完整调用cmd命令,在不重启cmd进程的情况下连续执行cmd命令,并获得执行结果,全后台执行不弹黑框。

由于需求所迫,网上现有资料中都无法找到C#完整连续调用cmd命令的资料。于是自己研究了一番,现有资料都说C#调用cmd命令时必须要加“exit”或者把cmd进程Close后才会有运行结果,其实不然。之所以要等进程结束才会有结果,是因为cmd在输出结束后会等待下一次输入,从而造成线程阻塞,就相当于C#控制台的Console.ReadLine()会造成线程阻塞一样。

既然需要等待输入会造成线程阻塞,那我们就把输入和输出线程分开就能解决这个问题。

看效果:


以下是封装好的代码:

2020/10/12更新:修复偶尔最后几行输出不完整问题。以前使用此类出现问题的请更新一下代码

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Threading;


/// <summary>
/// 控制台命令,由天蘩封装
/// </summary>
public class Command
{
        private const int _ReadSize = 1024;
        private Process _CMD;//cmd进程
        private Encoding _OutEncoding;//输出字符编码
        private Stream _OutStream;//基础输出流
        private Stream _ErrorStream;//错误输出流
        public event Action<string> Output;//输出事件
        public event Action<string> Error;//错误事件
        public event Action Exited;//退出事件
        private bool _Run;//循环控制
        private byte[] _TempBuffer;//临时缓冲
        private byte[] _ReadBuffer;//读取缓存区

        private byte[] _ETempBuffer;//临时缓冲
        private byte[] _ErrorBuffer;//错误读取缓存区
        public Command()
        {
                _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 += _CMD_Exited;
                _ReadBuffer = new byte[_ReadSize];
                _ErrorBuffer = new byte[_ReadSize];
                ReStart();
        }

        /// <summary>
        /// 停止使用,关闭进程和循环线程
        /// </summary>
        public void Stop()
        {
                _Run = false;
                _CMD.Close();
        }


        /// <summary>
        /// 重新启用
        /// </summary>
        public void ReStart()
        {
                Stop();
                _CMD.Start();
                _OutEncoding = _CMD.StandardOutput.CurrentEncoding;
                _OutStream = _CMD.StandardOutput.BaseStream;
                _ErrorStream = _CMD.StandardError.BaseStream;
                _Run = true;
                _CMD.StandardInput.AutoFlush = true;
                ReadResult();
                ErrorResult();
        }

        //退出事件
        private void _CMD_Exited(object sender, EventArgs e)
        {
                Exited?.Invoke();
        }

        /// <summary>
        /// 执行cmd命令
        /// </summary>
        /// <param name="cmd">需要执行的命令</param>
        public void RunCMD(string cmd)
        {

                if (!_Run)
                {
                        if (cmd.Trim().Equals("/restart", StringComparison.CurrentCultureIgnoreCase))
                        {
                                ReStart();
                        }
                        return;
                }
                if (_CMD.HasExited)
                {
                        Stop();
                        return;
                }
                _CMD.StandardInput.WriteLine(cmd);
        }



        //异步读取输出结果
        private void ReadResult()
        {
                if (!_Run)
                {
                        return;
                }
                _OutStream.BeginRead(_ReadBuffer, 0, _ReadSize, ReadEnd, null);
        }

        //一次异步读取结束
        private void ReadEnd(IAsyncResult ar)
        {
                int count = _OutStream.EndRead(ar);

                if (count < 1)
                {
                        if (_CMD.HasExited)
                        {
                                Stop();
                        }
                        return;
                }

                if (_TempBuffer == null)
                {
                        _TempBuffer = new byte[count];
                        Buffer.BlockCopy(_ReadBuffer, 0, _TempBuffer, 0, count);
                }
                else
                {
                        byte[] buff = _TempBuffer;
                        _TempBuffer = new byte[buff.Length + count];
                        Buffer.BlockCopy(buff, 0, _TempBuffer, 0, buff.Length);
                        Buffer.BlockCopy(_ReadBuffer, 0, _TempBuffer, buff.Length, count);
                }

                if (count < _ReadSize)
                {
                        string str = _OutEncoding.GetString(_TempBuffer);
                        Output?.Invoke(str);
                        _TempBuffer = null;
                }

                ReadResult();
        }


        //异步读取错误输出
        private void ErrorResult()
        {
                if (!_Run)
                {
                        return;
                }
                _ErrorStream.BeginRead(_ErrorBuffer, 0, _ReadSize, ErrorCallback, null);
        }

        private void ErrorCallback(IAsyncResult ar)
        {
                int count = _ErrorStream.EndRead(ar);

                if (count < 1)
                {
                        if (_CMD.HasExited)
                        {
                                Stop();
                        }
                        return;
                }

                if (_ETempBuffer == null)
                {
                        _ETempBuffer = new byte[count];
                        Buffer.BlockCopy(_ErrorBuffer, 0, _ETempBuffer, 0, count);
                }
                else
                {
                        byte[] buff = _ETempBuffer;
                        _ETempBuffer = new byte[buff.Length + count];
                        Buffer.BlockCopy(buff, 0, _ETempBuffer, 0, buff.Length);
                        Buffer.BlockCopy(_ErrorBuffer, 0, _ETempBuffer, buff.Length, count);
                }

                if (count < _ReadSize)
                {
                        string str = _OutEncoding.GetString(_ETempBuffer);
                        Error?.Invoke(str);
                        _ETempBuffer = null;
                }

                ErrorResult();
        }

        ~Command()
        {
                _Run = false;
                _CMD?.Close();
                _CMD?.Dispose();
        }

}


调用示例:

        internal class Program
        {
                private static void Main(string[] args)
                {
                        Command command = new Command();
                        command.Output += Command_Output;
                        command.Error += Command_Error;
                        command.Exited += Command_Exited;

                        while (true)
                        {
                                string cmd = Console.ReadLine();
                                command.RunCMD(cmd);
                        }

                }

                private static void Command_Exited()
                {
                        Console.WriteLine("已退出");
                }

                private static void Command_Error(string msg)
                {
                        Console.Write(msg);
                }

                private static void Command_Output(string msg)
                {
                        Console.Write(msg);
                }
        }
  • 68
    点赞
  • 57
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
你可以使用 `Process` 类来执行 cmd 命令,并且使用 `StandardInput` 属性来写入命令。要实现你所需的功能,你可以将 `Process` 对象和一个标志变量一起存储在类的成员变量中,如下所示: ```csharp public class CommandRunner { private Process _process; private bool _isRunning = false; public async Task RunCommand(string command) { if (_isRunning) { Console.WriteLine("Previous command is still running, skipping..."); return; } _process = new Process(); _process.StartInfo.FileName = "cmd.exe"; _process.StartInfo.Arguments = "/c " + command; _process.StartInfo.UseShellExecute = false; _process.StartInfo.RedirectStandardInput = true; _process.StartInfo.RedirectStandardOutput = true; _isRunning = true; _process.Start(); await _process.StandardInput.WriteLineAsync(command); // Wait for the command to complete await _process.WaitForExitAsync(); _isRunning = false; } } ``` 在 `RunCommand` 方法中,我们首先检查是否有上一个命令正在运,如果是,则跳过。否则,我们创建一个新的 `Process` 对象并执行 cmd 命令。我们使用 `_isRunning` 标志变量来跟踪是否有命令正在运,并在命令完成后将其设置为 `false`。请注意,我们使用 `await` 关键字来等待命令完成。此外,我们在 `ProcessStartInfo` 中设置了 `RedirectStandardInput` 属性,以便能够向 cmd 进程中写入命令。 你可以像这样使用 `CommandRunner` 类来运命令: ```csharp var runner = new CommandRunner(); await runner.RunCommand("dir"); await runner.RunCommand("ping google.com"); ``` 在这个示例中,我们创建了一个新的 `CommandRunner` 实例,并使用它来运两个命令:`dir` 和 `ping google.com`。如果第一个命令还没有完成,则第二个命令将被跳过。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值