日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > C# >内容正文

C#

使用 C# 捕获进程输出

發(fā)布時(shí)間:2023/12/4 C# 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 使用 C# 捕获进程输出 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

在 .net 中捕獲進(jìn)程輸出

Intro

很多時(shí)候我們可能會(huì)需要執(zhí)行一段命令獲取一個(gè)輸出,遇到的比較典型的就是之前我們需要用 FFMpeg 實(shí)現(xiàn)視頻的編碼壓縮水印等一系列操作,當(dāng)時(shí)使用的是 FFMpegCore 這個(gè)類庫(kù),這個(gè)類庫(kù)的實(shí)現(xiàn)原理是啟動(dòng)另外一個(gè)進(jìn)程,啟動(dòng) ffmpeg 并傳遞相應(yīng)的處理參數(shù),并根據(jù)進(jìn)程輸出獲取處理進(jìn)度,處理結(jié)果等信息

為了方便使用,實(shí)現(xiàn)了兩個(gè)幫助類來(lái)方便的獲取進(jìn)程的輸出,分別是 ProcessExecutor 和 CommandRunner,前者更為靈活,可以通過事件添加自己的額外事件訂閱處理,后者為簡(jiǎn)化版,主要是只獲取輸出的場(chǎng)景,兩者的實(shí)現(xiàn)原理大體是一樣的,啟動(dòng)一個(gè) Process,并監(jiān)聽其輸出事件獲取輸出

ProcessExecutor

使用示例,這個(gè)示例是獲取保存 nuget 包的路徑的一個(gè)示例:

using?var?executor?=?new?ProcessExecutor("dotnet",?"nuget?locals?global-packages?-l"); var?folder?=?string.Empty; executor.OnOutputDataReceived?+=?(sender,?str)?=> {if(str?is?null)return;Console.WriteLine(str);if(str.StartsWith("global-packages:")){folder?=?str.Substring("global-packages:".Length).Trim();????????????????????} }; executor.Execute();Console.WriteLine(folder);

ProcessExecutor 實(shí)現(xiàn)代碼如下:

public?class?ProcessExecutor?:?IDisposable {public?event?EventHandler<int>?OnExited;public?event?EventHandler<string>?OnOutputDataReceived;public?event?EventHandler<string>?OnErrorDataReceived;protected?readonly?Process?_process;protected?bool?_started;public?ProcessExecutor(string?exePath)?:?this(new?ProcessStartInfo(exePath)){}public?ProcessExecutor(string?exePath,?string?arguments)?:?this(new?ProcessStartInfo(exePath,?arguments)){}public?ProcessExecutor(ProcessStartInfo?startInfo){_process?=?new?Process(){StartInfo?=?startInfo,EnableRaisingEvents?=?true,};_process.StartInfo.UseShellExecute?=?false;_process.StartInfo.CreateNoWindow?=?true;_process.StartInfo.RedirectStandardOutput?=?true;_process.StartInfo.RedirectStandardInput?=?true;_process.StartInfo.RedirectStandardError?=?true;}protected?virtual?void?InitializeEvents(){_process.OutputDataReceived?+=?(sender,?args)?=>{if?(args.Data?!=?null){OnOutputDataReceived?.Invoke(sender,?args.Data);}};_process.ErrorDataReceived?+=?(sender,?args)?=>{if?(args.Data?!=?null){OnErrorDataReceived?.Invoke(sender,?args.Data);}};_process.Exited?+=?(sender,?args)?=>{if?(sender?is?Process?process){OnExited?.Invoke(sender,?process.ExitCode);}else{OnExited?.Invoke(sender,?_process.ExitCode);}};}protected?virtual?void?Start(){if?(_started){return;}_started?=?true;_process.Start();_process.BeginOutputReadLine();_process.BeginErrorReadLine();_process.WaitForExit();}public?async?virtual?Task?SendInput(string?input){try{await?_process.StandardInput.WriteAsync(input!);}catch?(Exception?e){OnErrorDataReceived?.Invoke(_process,?e.ToString());}}public?virtual?int?Execute(){InitializeEvents();Start();return?_process.ExitCode;}public?virtual?async?Task<int>?ExecuteAsync(){InitializeEvents();return?await?Task.Run(()?=>{Start();return?_process.ExitCode;}).ConfigureAwait(false);}public?virtual?void?Dispose(){_process.Dispose();OnExited?=?null;OnOutputDataReceived?=?null;OnErrorDataReceived?=?null;} }

CommandExecutor

上面的這種方式比較靈活但有些繁瑣,于是有了下面這個(gè)版本

使用示例:

[Fact] public?void?HostNameTest() {if?(!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)){return;}var?result?=?CommandRunner.ExecuteAndCapture("hostname");var?hostName?=?Dns.GetHostName();Assert.Equal(hostName,?result.StandardOut.TrimEnd());Assert.Equal(0,?result.ExitCode); }

實(shí)現(xiàn)源碼:

public?static?class?CommandRunner {public?static?int?Execute(string?commandPath,?string?arguments?=?null,?string?workingDirectory?=?null){using?var?process?=?new?Process(){StartInfo?=?new?ProcessStartInfo(commandPath,?arguments????string.Empty){UseShellExecute?=?false,CreateNoWindow?=?true,WorkingDirectory?=?workingDirectory????Environment.CurrentDirectory}};process.Start();process.WaitForExit();return?process.ExitCode;}public?static?CommandResult?ExecuteAndCapture(string?commandPath,?string?arguments?=?null,?string?workingDirectory?=?null){using?var?process?=?new?Process(){StartInfo?=?new?ProcessStartInfo(commandPath,?arguments????string.Empty){UseShellExecute?=?false,CreateNoWindow?=?true,RedirectStandardOutput?=?true,RedirectStandardError?=?true,WorkingDirectory?=?workingDirectory????Environment.CurrentDirectory}};process.Start();var?standardOut?=?process.StandardOutput.ReadToEnd();var?standardError?=?process.StandardError.ReadToEnd();process.WaitForExit();return?new?CommandResult(process.ExitCode,?standardOut,?standardError);} }public?sealed?class?CommandResult {public?CommandResult(int?exitCode,?string?standardOut,?string?standardError){ExitCode?=?exitCode;StandardOut?=?standardOut;StandardError?=?standardError;}public?string?StandardOut?{?get;?}public?string?StandardError?{?get;?}public?int?ExitCode?{?get;?} }

More

如果只要執(zhí)行命令獲取是否執(zhí)行成功則使用 CommandRunner.Execute 即可,只獲取輸出和是否成功可以用 CommandRunner.ExecuteAndCapture 方法,如果想要進(jìn)一步的添加事件訂閱則使用 ProcessExecutor

Reference

  • https://github.com/rosenbjerg/FFMpegCore

  • https://github.com/WeihanLi/WeihanLi.Common/blob/dev/src/WeihanLi.Common/Helpers/ProcessExecutor.cs

  • https://github.com/WeihanLi/WeihanLi.Common/blob/dev/test/WeihanLi.Common.Test/HelpersTest/ProcessExecutorTest.cs

  • https://github.com/WeihanLi/WeihanLi.Common/blob/dev/test/WeihanLi.Common.Test/HelpersTest/CommandRunnerTest.cs

總結(jié)

以上是生活随笔為你收集整理的使用 C# 捕获进程输出的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。