【问题标题】:How to get Output of a Command Prompt Window line by line in Visual Basic?如何在 Visual Basic 中逐行获取命令提示符窗口的输出?
【发布时间】:2014-10-14 18:54:26
【问题描述】:

我正在尝试逐行获取命令行输出,直到输出结束,但我无法这样做。我在我的表单中使用它,此代码在单击按钮时执行。
你能告诉我我的代码有什么问题吗?

Dim proc As ProcessStartInfo = New ProcessStartInfo("cmd.exe")
    Dim pr As Process
    proc.CreateNoWindow = True
    proc.UseShellExecute = False
    proc.RedirectStandardInput = True
    proc.RedirectStandardOutput = True
    pr = Process.Start(proc)
    pr.StandardInput.WriteLine("cd C:\sdk\platform-tools\")
    pr.StandardInput.WriteLine("adb help")
    Dim helpArray(20) as String
    For i as Integer 1 To 7
    helpArray(i) = pr.StandardOutput.ReadLine()
    Next
    pr.StandardOutput.Close()

执行此代码时程序停止响应。

【问题讨论】:

    标签: vb.net cmd


    【解决方案1】:

    我做了一些研究。 adb help 将输出写入 STDERR。所以你需要这样的东西:

        Dim proc As ProcessStartInfo = New ProcessStartInfo("cmd.exe")
        Dim pr As Process
        proc.CreateNoWindow = True
        proc.UseShellExecute = False
        proc.RedirectStandardInput = True
        proc.RedirectStandardOutput = True
        pr = Process.Start(proc)
        pr.StandardInput.WriteLine("C:\sdk\platform-tools")
        pr.StandardInput.WriteLine("adb help 2>&1")
        pr.StandardInput.Close()
        Console.WriteLine(pr.StandardOutput.ReadToEnd())
        pr.StandardOutput.Close()
    

    抓住它。
    例如,如果您调用 ipconfig,则不需要 2>&1。

    【讨论】:

    • 还有RedirectStandardError
    • 嗨@Dmitry Kurilo 我已经尝试过你建议的这种方法。多谢兄弟。但问题是我想将每一行输出放到一个单独的字符串中。稍后我将合并想要的行并省略不需要的行。它不仅仅是为了 adb 的帮助。我还想使用其他一些 adb 命令。你明白我想要做什么吗?不过谢谢。
    • 嗨@Dmitry Kurilo。非常感谢兄弟。我解决了我的问题。在再次查看您的代码后,我意识到我已经忘记了这一行。 “pr.StandardInput.Close()”。我没有把它放在我的代码中。现在工作正常。多谢兄弟。上帝祝福你。在我向 Patsy 道歉让他对我的代码不屑一顾后,我会给你一个绿色的勾
    【解决方案2】:

    不要对输出进行交互,也不要阅读它!通常你不知道输出有多长(错误输出也是如此),所以你需要准备一个未知的长度。既然你告诉 Process 类,你想自己处理标准输出标准错误,你还需要bind to the events,在这种情况下:

    • OutputDataReceived
    • 错误数据接收

    或者像@Dmitry Kurilo 在他的回答中所做的那样阻止当前进程并立即读取完整的输出。我发现第一种方法更好,因为我不需要等待过程结束才能看到它的输出。 ProcessStartInfo.RedirectstandardError property 的 MSDN 文档通过大量示例很好地解释了不同的可能性。 如果你想走特定的路线,有很多可能性。一种是将每个输出(行)存储在委托中并稍后使用它,使用 List(Of String) 并在处理完成时输出特定行(= 所有输出行都存在)。

    可能的解决方案如下所示:

    ' store error output lines
    dim lines = new List(of String)
    
    dim executable = "c:\temp\android\sdk\platform-tools\adb.exe"
    dim arguments = " help"
    dim process = new Process()
    process.StartInfo = createStartInfo(executable, arguments)
    process.EnableRaisingEvents = true
    addhandler process.Exited, Sub (ByVal sender As Object, ByVal e As System.EventArgs) 
        Console.WriteLine(process.ExitTime)
        Console.WriteLine(". Processing done.")
        ' output line n when output is ready (= all lines are present)
        Console.WriteLine(lines(4))
    end sub
    ' catch standard output
    addhandler process.OutputDataReceived, Sub (ByVal sender As Object, ByVal e As System.Diagnostics.DataReceivedEventArgs) 
            if (not String.IsNullOrEmpty(e.Data))
                Console.WriteLine(String.Format("{0}> {1}", DateTime.Now.ToString("dd.MM.yyyy HH:mm:ss") ,e.Data))
            end if
    end sub
    ' catch errors
    addhandler process.ErrorDataReceived, Sub (ByVal sender As Object, ByVal e As System.Diagnostics.DataReceivedEventArgs) 
        'Console.WriteLine(String.Format("! {0}", e.Data))
        ' add every output line to the list of strings
        lines.Add(e.Data)
    end sub
    ' start process
    dim result = process.Start()
    ' and wait for output
    process.BeginOutputReadLine()
    ' and wait for errors :-)
    process.BeginErrorReadLine()
    
    private function createStartInfo(byval executable as String, byval arguments as String) as ProcessStartInfo
        dim processStartInfo = new ProcessStartInfo(executable, arguments)
        processStartInfo.WorkingDirectory = Path.GetDirectoryName(executable)
        ' we want to read standard output
        processStartInfo.RedirectStandardOutput = true
        ' we want to read the standard error
        processStartInfo.RedirectStandardError = true
        processStartInfo.UseShellExecute = false
        processStartInfo.ErrorDialog = false
        processStartInfo.CreateNoWindow = true
        return processStartInfo
    end function
    

    现在即使 adb 写入错误输出,您也可以看到它。它也将完成。

    本例中的输出如下所示:

    14.10.2014 12:49:10
    . Processing done.
     -e                            - directs command to the only running emulator.
    

    另一种可能性是将所有内容放入一个字符串中,并在该过程完成后将单个字符串拆分为行尾(CRLF \r\n),您将获得要过滤的行。

    【讨论】:

    • 我会放弃 if (not process.HasExited) 检查,否则您可能会丢失程序输出的最后一行。
    • @MarkHurd 感谢您的提示。我已经删除了这条线。
    • @pasty 我不只使用 adb help 命令。我也在使用 adb 的一些其他命令。我知道输出的长度可能会有所不同。假设输出行数为 20,我只是给出了一个 20 的数组字符串。但问题是我想获取每个输出行并将其保存在单独的字符串中。然后稍后我想通过仅使用所需的字符串来仅使用所需的轮廓而不是不需要的轮廓。如何将输出的每一行保存到单独的字符串中?
    • 我已经更新了我的答案 - 现在当过程完成时,只输出第 4 行。您可以根据需要更改代码。
    • 嗨@Pasty。我再次查看了 Dmitry Kurilo 的回答,我意识到我没有输入“pr.StandardInput.Close()”这一行。现在我已经做到了,并且工作正常。很抱歉让你经历了所有的麻烦。我想给你们两个打上绿色的勾号,但我不知道这是否可能。非常感谢人
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-21
    • 2011-05-11
    相关资源
    最近更新 更多