vb.net 如何在 Visual Basic 中逐行获取命令提示符窗口的输出?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/26347823/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-17 18:20:37  来源:igfitidea点击:

How to get Output of a Command Prompt Window line by line in Visual Basic?

vb.netcmd

提问by Devenom

I am trying to get a command line output line by line till the end of the output but I am not able to do so. I am using it in my Form and this code executes on click of a button.
Can you tell me whats wrong with my code?

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

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()

The program stops responding when this code is executed.

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

采纳答案by Dima Kurilo

I've done some research. adb help writes output into STDERR. So you need something like:

我做了一些研究。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()

to catch it.
You need no 2>&1 if you call ipconfig, for example.

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

回答by pasty

Do not interate over the output and do not read it! Normally you don't know how long the output (same goes for error output too) would be, so you need to prepare for an unknown length. Since you are telling the Process class, that you want to handle the standard outputand the standard errorby yourself, you also need to bind to the events, in this case:

不要对输出进行交互,也不要阅读它!通常你不知道输出的长度(错误输出也是如此),所以你需要准备一个未知的长度。由于您告诉 Process 类,您要自己处理标准输出标准错误,因此您还需要绑定到 events,在这种情况下:

  • OutputDataReceived
  • ErrorDataReceived
  • 输出数据接收
  • 收到错误数据

or to block the current process and read the complete output at once like @Dmitry Kurilo does in his answer. I find the first approach better because I do not need to wait for the process to end to see it's output. The MSDN documentation of the ProcessStartInfo.RedirectstandardError propertygives a good explanation of the different possibilities with a lot of examples. If you want to take a specific line, there are a lot of possibilities. One would be to store each output (line) in the delegate and use it later, using a List(Of String)and output the specific line when the process is done (= all output lines are present).

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

A possible solution could look like this:

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

' 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

Now even if the adbwrites to the error output, you will be able to see it. It will also be complete.

现在即使adb写入错误输出,您也能看到它。它也将是完整的。

The output in this case looks like this:

本例中的输出如下所示:

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

Another possibility would be to put everything into one string and after the process has finished split the single string on line endings (CRLF \r\n) and you will gain the lines you want to filter.

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