You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在C#中获取ADB.exe push命令的进程输出百分比?

问题描述

我正在开发一款向Android设备复制文件的应用。通过CMD或PowerShell执行adb push命令时,会显示文件复制的进度百分比,但使用以下C#代码时,无法实时重定向输出,仅在进程结束后才显示内容。我尝试创建CMD进程、ADB进程、PowerShell进程,均无效果。由于adb push耗时较长时用户会误以为程序卡顿,因此我希望实现实时显示进度(如进度条)的功能,以下是我使用的代码:

folderToLoad = txtOBBFolder.Text;
process = new Process();
process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
process.StartInfo.FileName = AppDomain.CurrentDomain.BaseDirectory + @"\adb.exe";
process.StartInfo.Arguments = @"push " + folderToLoad + " /sdcard/Android/obb/" + Path.GetFileName(folderToLoad);
process.StartInfo.WorkingDirectory = AppDomain.CurrentDomain.BaseDirectory;
process.StartInfo.UseShellExecute = false;
process.StartInfo.CreateNoWindow = true;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardInput = false;
process.Start();
q = "";
while (!process.HasExited)
{
    q += process.StandardOutput.ReadToEnd();
    q += process.StandardError.ReadToEnd();
    txtOutput.AppendText(q);
}
解决方案

当前代码的核心问题是ReadToEnd()方法会阻塞线程,必须等到进程输出流完全结束才返回内容,因此无法实时获取进度。正确的实现方式是利用进程的异步事件监听输出,每次有新内容输出时立即触发回调,同时处理跨线程更新UI的问题。

以下是修改后的完整代码示例:

private void StartAdbPush()
{
    string folderToLoad = txtOBBFolder.Text;
    Process process = new Process();
    
    process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
    process.StartInfo.FileName = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "adb.exe");
    // 用字符串插值和引号包裹路径,避免含空格的路径引发错误
    process.StartInfo.Arguments = $"push \"{folderToLoad}\" /sdcard/Android/obb/{Path.GetFileName(folderToLoad)}";
    process.StartInfo.WorkingDirectory = AppDomain.CurrentDomain.BaseDirectory;
    process.StartInfo.UseShellExecute = false;
    process.StartInfo.CreateNoWindow = true;
    process.StartInfo.RedirectStandardError = true;
    process.StartInfo.RedirectStandardOutput = true;
    process.StartInfo.RedirectStandardInput = false;

    // 绑定标准输出监听事件
    process.OutputDataReceived += (sender, e) =>
    {
        if (!string.IsNullOrEmpty(e.Data))
        {
            // 切换到UI线程更新控件,避免跨线程异常
            txtOutput.Invoke(new Action(() =>
            {
                txtOutput.AppendText(e.Data + Environment.NewLine);
                // 解析输出中的进度百分比,更新进度条
                if (e.Data.Contains("%"))
                {
                    // 提取进度数字(适配adb push的输出格式,比如"10% 1234KB/s")
                    string[] parts = e.Data.Split(new[] {'%', ' '}, StringSplitOptions.RemoveEmptyEntries);
                    if (int.TryParse(parts[0], out int progress))
                    {
                        progressBar.Value = progress;
                    }
                }
            }));
        }
    };

    // 绑定错误输出监听事件
    process.ErrorDataReceived += (sender, e) =>
    {
        if (!string.IsNullOrEmpty(e.Data))
        {
            txtOutput.Invoke(new Action(() =>
            {
                txtOutput.AppendText($"[错误] {e.Data}" + Environment.NewLine);
            }));
        }
    };

    process.Start();
    // 启动异步读取输出流
    process.BeginOutputReadLine();
    process.BeginErrorReadLine();

    // 可选:等待进程结束后释放资源,也可在外部通过Exited事件处理
    process.WaitForExit();
    process.Dispose();
}

关键优化点

  • 替换阻塞式的ReadToEnd()为BeginOutputReadLine()/BeginErrorReadLine(),实现异步实时读取
  • 通过OutputDataReceived/ErrorDataReceived事件捕获每一行输出,即时更新UI
  • 使用Control.Invoke()切换到UI线程操作控件,解决跨线程访问异常
  • 优化路径拼接和参数格式,用Path.Combine()和引号包裹路径,避免特殊字符导致的命令错误
  • 增加进度解析逻辑,从adb输出中提取百分比,直接更新进度条控件

内容的提问来源于stack exchange,提问作者Paulo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 00:30:38