运行一个命令行程序,并得到输出而处理仍在运行? [英] Run a commandline process and get the output while that process is still running?

查看:204
本文介绍了运行一个命令行程序,并得到输出而处理仍在运行?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何,我可以运行一个命令行程序,并得到输出而进程仍在运行?

我的意思是用自身的进度运行CLI过程中,可执行文件本身需要很长的时间来完成操作,所以我想利用从自己的过程,进度信息显示在我的应用程序的进展情况,另一种方式我没有任何信息显示进度,直到过程完成。

我工作在一个WindowsForm项目,而不是一个控制台应用程序。

我试图做使用FFMPEG.exe(64)同样的,我可以读进步,而FFmpeg中运行时,我可以从FFMPEG挑选的进展,并做我想做的,但与此可执行我不能做到这一点,我不知道是否是可能的。

该计划是dbPowerAmp CoreConverter,这是一个音乐转换,我认为该计划将所有输出在统一code编码,因为读书,我需要设置输出编码统一code的输出。

...另一个问题是我无法找到一个方法来读取,即使使用统一code这个过程的standardError输出,所以请,如果有人能帮助我与这两个问题。

下面是应用程序: HTTP://www.dbpoweramp .COM /安装/ DMC-R14.4-REF-Trial.exe

下面是该方案的直接从CMD推出了一个示例输出:

(我需要的是挑进度*星号量,而进程正在运行,以计算和显示这一比例还在我的应用程序)

和这里是我的code:

 私人共享CoreConverter随着新工艺()

私人共享CoreConverter_Info作为新的ProcessStartInfo()用{_
              .CreateNoWindow = TRUE,_
              .UseShellExecute =假,_
              .RedirectStandardOutput = TRUE,_
              .RedirectStandardError =真_
}

私人共享子Run_CoreConverter()


    只是为了测试CMD统一code输出:
    
    'CoreConverter_Info.FileName =CMD
    CoreConverter_Info.Arguments =/ U /CC:\CoreConverter.exe&放大器; CoreConverter_Info.Arguments


    CoreConverter_Info.FileName =C:\ CoreConverter.exe
    CoreConverter_Info.Arguments =的String.Format( -  INFILE ={0}-outfile ={1}-convert_to =MP3(拉梅),......,等等等等等等)
    CoreConverter_Info.StandardErrorEncoding = System.Text.Encoding.Uni code
    CoreConverter_Info.StandardOutputEncoding = System.Text.Encoding.Uni code
    CoreConverter.StartInfo = CoreConverter_Info
    CoreConverter.EnableRaisingEvents = TRUE
    CoreConverter.Start()
    CoreConverter.WaitForExit()


    昏暗readerStdOut作为IO.StreamReader = CoreConverter.StandardOutput

    这部分作品FFMPEG可执行文件,但不与Coreconverter.exe,
    我的意思是,当CoreConverter.exe完成显示MSGBOX :(
    但与FFMPEG我可以读取输出,同时FFMPEG仍在运行。
    虽然CoreConverter.StandardOutput.EndOfStream = TRUE
        MSGBOX(CoreConverter.StandardOutput.ReadLine)
    结束在

    如果CoreConverter.Exit code<> 0然后
        抛出新的异常(CoreConverter.StandardError.ReadToEnd)

        没办法读ERROROUTPUT ...
        的MessageBox.show(CoreConverter.StandardError.ReadToEnd,CoreConverter,MessageBoxButtons.OK,MessageBoxIcon.Error)

        的MessageBox.show(CoreConverter.StandardOutput.ReadToEnd,CoreConverter,MessageBoxButtons.OK,MessageBoxIcon.Error)
    结束如果

结束小组
 

  

更新:

我真的很desesperated,我所有的意图是史诗般的失败,我已经尝试了所有我什么技能可以做(但不多)。

即使使用多线程在一个独立的线程运行一个进程,而我尝试从主线程的输出,我不能尝试恢复过程的输出,直到程序退出,这太疯狂了!我不明白为什么发生这种情况。

仅仅是一个疯狂的东西在那里,我失去了很多小时的一天,有人告诉我,也许做一个COM对象,我可以做到这一点,好了,我不想花时间学习如何做一个COM对象只挑选一对夫妇从控制台的字符,这几个月的学习,不会帮助我更多的东西在我的生活,简单地说,我需要一些更基本的,读取缓冲区控制台可以工作,也许这个想法,但肯定我将无法读取缓冲区,直到进程退出,就这样。

所以。我能做些什么这个该死的进程?

只是为了让更多的比我的问题说我自己的desesperation的话,我会在这里贴了多线程的事情,我已经试过了更新。

......就像我已经说过,我不能尝试读取,而过程中仍然乳宁的输出和错误输出只是不能readed(字符串始终是空的),即使该过程完成(与善意错误ofcourse)。

 公共共享error_output作为字符串
公共共享standard_output作为字符串
公共共享活跃布尔=假'CoreConverter线程处于活动状态?

公共共享MyThread作为Threading.Thread =新Threading.Thread(AddressOf Run_CoreConverter)

公共共享子Convert_To_MP3(BYVAL In_File作为字符串_

' 等等等等等等
Run_CoreConverter()

    MyThread =新Threading.Thread(AddressOf Run_CoreConverter)
    MyThread.IsBackground = TRUE
    积极= TRUE
    MyThread.Start()
    Get_Output()

结束小组

公共共享子Get_Output()

虽然主动虽然Coreconverter.exe是乳宁...

    尝试
        如果不CoreConverter.HasExited然后
            MSGBOX(CoreConverter.StandardOutput.ReadToEnd)这将不显示,直到进程已退出...
        结束如果
    抓住EX为例外

    结束尝试

    如果error_output状态并没有任何然后
        MSGBOX(error_output)这将不显示,直到进程已退出...
    结束如果

    如果standard_output状态并没有任何然后
        MSGBOX(standard_output)这将不显示,直到进程已退出...
    结束如果

结束在

MSGBOX(结束当前)

结束小组

公共共享子Run_CoreConverter()
    CoreConverter_Info.FileName = CoreConverter_Location
    CoreConverter_Info.StandardErrorEncoding = System.Text.Encoding.Uni code
    CoreConverter_Info.StandardOutputEncoding = System.Text.Encoding.Uni code
    CoreConverter.StartInfo = CoreConverter_Info
    CoreConverter.EnableRaisingEvents =假

    CoreConverter.Start()
    CoreConverter.WaitForExit()

    'Threading.Thread.Sleep(2000)
    如果X为整数= 0〜99999999
    error_output = CoreConverter.StandardError.ReadToEnd
    standard_output = CoreConverter.StandardOutput.ReadToEnd
    ' 下一个

    如果CoreConverter.Exit code<> 0然后
        抛出新的异常(CoreConverter.StandardError.ReadToEnd)
         的MessageBox.show(CoreConverter.StandardError.ReadToEnd,CoreConverter,MessageBoxButtons.OK,MessageBoxIcon.Error)
         的MessageBox.show(CoreConverter.StandardOutput.ReadToEnd,CoreConverter,MessageBoxButtons.OK,MessageBoxIcon.Error)
    结束如果

    CoreConverter.Close()
    激活=假

结束小组
 

解决方案

我觉得有可能是在dbPowerAmp的编码错误。输出在CMD.EXE / U统一code环境看起来不错,但似乎当你连接一台净Process对象,它结束了在字符之间空字节。您可以解决此通过之间的良好UTF8字丢弃的空字节。

我在PowerShell中更流畅,所以这里是我写的证明,这将工作。

  $ progressCounter = 0.0
$ progressScaleString =0%----------- 25%----------- 50%----------- 75% -   -   -   - ------ 100%
$ PSI =新的对象system.diagnostics.processstartinfo
$ psi.FileName =C:\ Program Files文件(x86)的\图说\ dBpoweramp \ CoreConverter.exe
#白鲸有声读物提供AT< HTTP://ia600208.us.archive.org/0/items/moby_dick_librivox/mobydick_135_melville.mp3>
$ psi.arguments ='-infile =C:\有声读物\ mobydick_135_melville.mp3-outfile =C:\有声读物\ mobydick_135_melville.flac-convert_to =后手-encoding =慢
$ psi.StandardOutputEncoding = [System.Text.Encoding] ::统一code
$ psi.RedirectStandardOutput = $真
$ psi.UseShellExecute = $假
$ PROC =新对象的System.Diagnostics.Process
$ proc.StartInfo = $ PSI
$ proc.Start();
#Look的魔法进度条串
$ outputBuf =
而($真){$ CHR = [字符] $ proc.StandardOutput.BaseStream.ReadByte();如果($ CHR -ne [字符] 0){$ outputBuf + = $ CHR; }如果($ outputBuf.Contains($ progressScaleString)){打破; }其他{入睡0.01; }}
#我们已经看到了进步的统治者,现在就开始数着点。
而($ progressCounter -le 100.0){$ CHR = $ proc.StandardOutput.BaseStream.ReadByte();如果($ CHR -lt 0){中断;}如果([字符] $ CHR -eq [字符]*){$ progressCounter + = 100.0 /($ progressScaleString.Length + 1);写主机$ progressCounter; }}
 

下面是我的裂缝移植这VB;只是一个工作线程运行和钩PercentDone到你的用户界面:

 公共事件PercentDone(BYVAL百分比为float)

私人共享CoreConverter随着新工艺()

私人共享CoreConverter_Info作为新的ProcessStartInfo()用{_
              .CreateNoWindow = TRUE,_
              .UseShellExecute =假,_
              .RedirectStandardOutput = TRUE,_
              .RedirectStandardError =真_
}

私人共享子Run_CoreConverter()

    昏暗ProgressScaleString作为字符串=0%----------- 25%----------- 50%----------- 75%--- -------- 100%
    昏暗ProgressCounter为float = 0.0

    CoreConverter_Info.FileName =C:\ CoreConverter.exe
    CoreConverter_Info.Arguments =的String.Format( -  INFILE ={0}-outfile ={1}-convert_to =MP3(拉梅),......,等等等等等等)
    CoreConverter_Info.StandardErrorEncoding = System.Text.Encoding.Uni code
    CoreConverter_Info.StandardOutputEncoding = System.Text.Encoding.Uni code
    CoreConverter.StartInfo = CoreConverter_Info
    CoreConverter.Start()

    昏暗OutputBuf作为字符串=
    昏暗CHR为字节;
    虽然真
      CHR = CoreConverter.StandardOutput.BaseStream.ReadByte();
      如果CHR< 0然后
        出口虽然
      elseif的CHR<> 0
        OutputBuf + = CTYPE(CHR,CHAR)
      结束如果
      如果OutputBuf.Contains(ProgressScaleString)然后
        出口虽然
      其他
        System.Threading.Thread.Sleep(10)
      结束如果
    结束在

    虽然ProgressCounter< = 100
      CHR = CoreConverter.StandardOutput.BaseStream.ReadByte()
      如果CHR< = 0然后
        出口虽然
      结束如果
      如果CHR == CTYPE(*C,字符),然后
        ProgressCounter + = 100.0 /($ progressScaleString.Length + 1)
        的RaiseEvent PercentDone(ProgressCounter)
      结束如果
    结束在

结束小组
 

How I can run a commandline process and get the output while that process is still running?

What I mean is to run a CLI process with its own progressbar, the executable itself takes a long time to finish the operation so I want to take that progress information from the own process to display the progress in my application, other way I don't have any info to display a progress until process finishes.

I'm working in a WindowsForm project, not a Console App.

I've tried to do the same using FFMPEG.exe (x64) and I can read the "progress" while FFMPEG is running, I can pick the progress from FFMPEG and do what I want, but with this executable I just can't do it and I don't know if is possible.

The program is "dbPowerAmp CoreConverter", it's a music converter, I think the program sends all the outputs in Unicode encoding because to read the output I need to set the output encoding to Unicode.

...Other problem is I can't find a way to read the StandardError output of this process even using Unicode so please if someone can help me with those two problems.

Here is the application: http://www.dbpoweramp.com/install/dMC-R14.4-Ref-Trial.exe

Here is an example output of the program launched directly from CMD:

(What I need is to pick the progressbar " * " asterisk character amount while process is running to calculate and display that percentage also in my application)

And here is my code:

Private Shared CoreConverter As New Process()

Private Shared CoreConverter_Info As New ProcessStartInfo() With { _
              .CreateNoWindow = True, _
              .UseShellExecute = False, _
              .RedirectStandardOutput = True, _
              .RedirectStandardError = True _
}

Private Shared Sub Run_CoreConverter()


    ' Just for testing CMD Unicode output:
    '
    ' CoreConverter_Info.FileName = "cmd"
    ' CoreConverter_Info.Arguments = "/U /C C:\CoreConverter.exe " & CoreConverter_Info.Arguments


    CoreConverter_Info.FileName = "C:\CoreConverter.exe"
    CoreConverter_Info.Arguments = String.Format("-infile=""{0}"" -outfile=""{1}"" -convert_to=""mp3 (Lame)""" ..., blah blah blah)
    CoreConverter_Info.StandardErrorEncoding = System.Text.Encoding.Unicode
    CoreConverter_Info.StandardOutputEncoding = System.Text.Encoding.Unicode
    CoreConverter.StartInfo = CoreConverter_Info
    CoreConverter.EnableRaisingEvents = True
    CoreConverter.Start()
    CoreConverter.WaitForExit()


    Dim readerStdOut As IO.StreamReader = CoreConverter.StandardOutput

    ' This part works with FFMPEG executable but not with Coreconverter.exe,
    ' What I mean is that the msgbox is displayed when CoreConverter.exe finishes :( 
    ' but with FFMPEG I can read the output while FFMPEG still running.
    While CoreConverter.StandardOutput.EndOfStream = True
        MsgBox(CoreConverter.StandardOutput.ReadLine)
    End While

    If CoreConverter.ExitCode <> 0 Then
        ' Throw New Exception(CoreConverter.StandardError.ReadToEnd)

        ' No way to read the ErrorOutput...
        MessageBox.Show(CoreConverter.StandardError.ReadToEnd, "CoreConverter", MessageBoxButtons.OK, MessageBoxIcon.Error)

        MessageBox.Show(CoreConverter.StandardOutput.ReadToEnd, "CoreConverter", MessageBoxButtons.OK, MessageBoxIcon.Error)
    End If

End Sub

UPDATE:

Really I'm so desesperated, all of my intents are epic fails, I've tried all what my skills can do (but that is not much).

Even using multithread to run a process in a separated thread while I try to get the output from the main thread I can't try to retrieve the process output until the process exited, it's crazy!, I don't understand why this happens.

Just is a crazy thing where I'm loosing a lot of hours by day, some people tell me that perhaps making a COM Object I can do it, well, I don't want to spent months learning how to make a COM Object just to pick a couple of characters from console, That months learning that would not help me with anything more in my life, simply as that, I need something more basic, maybe the idea of reading the buffer console could work, but sure I would not be able to read the buffer until the process exited, so.

So. What can I do with this damn process?

Just to make more than an update of my question to say my own desesperation words I will paste here a multi thread thing I've tried.

...Like I've said I can't try to read the outputs while process still runing, and the error output just can't be readed (string always is empty) even when the process finishes (with an intentioned error ofcourse).

Public Shared error_output As String
Public Shared standard_output As String
Public Shared active As Boolean = False ' CoreConverter Thread is active?

Public Shared MyThread As Threading.Thread = New Threading.Thread(AddressOf Run_CoreConverter)

Public Shared Sub Convert_To_MP3(ByVal In_File As String, _

' blah blah blah
'Run_CoreConverter()

    MyThread = New Threading.Thread(AddressOf Run_CoreConverter)
    ' MyThread.IsBackground = True
    active = True
    MyThread.Start()
    Get_Output()

End Sub

Public Shared Sub Get_Output()

While active ' While Coreconverter.exe is runing...

    Try
        If Not CoreConverter.HasExited Then
            MsgBox(CoreConverter.StandardOutput.ReadToEnd) ' This will not be displayed until process has exited...
        End If
    Catch ex As Exception

    End Try

    If error_output IsNot Nothing Then
        MsgBox(error_output) ' This will not be displayed until process has exited...
    End If

    If standard_output IsNot Nothing Then
        MsgBox(standard_output) ' This will not be displayed until process has exited...
    End If

End While

MsgBox("end active")

End Sub

Public Shared Sub Run_CoreConverter()
    CoreConverter_Info.FileName = CoreConverter_Location
    CoreConverter_Info.StandardErrorEncoding = System.Text.Encoding.Unicode
    CoreConverter_Info.StandardOutputEncoding = System.Text.Encoding.Unicode
    CoreConverter.StartInfo = CoreConverter_Info
    CoreConverter.EnableRaisingEvents = False

    CoreConverter.Start()
    ' CoreConverter.WaitForExit()

    ' Threading.Thread.Sleep(2000)
    ' For x As Integer = 0 To 99999999
    error_output = CoreConverter.StandardError.ReadToEnd
    standard_output = CoreConverter.StandardOutput.ReadToEnd
    ' Next

    If CoreConverter.ExitCode <> 0 Then
        Throw New Exception(CoreConverter.StandardError.ReadToEnd)
         MessageBox.Show(CoreConverter.StandardError.ReadToEnd, "CoreConverter", MessageBoxButtons.OK, MessageBoxIcon.Error)
         MessageBox.Show(CoreConverter.StandardOutput.ReadToEnd, "CoreConverter", MessageBoxButtons.OK, MessageBoxIcon.Error)
    End If

    CoreConverter.Close()
    active = False

End Sub

解决方案

I think there may be bugs in dbPowerAmp's encoding. The output looks great in a cmd.exe /u Unicode environment, but it seems when you hook up a .Net Process object, it ends up with null bytes in between characters. You can work around this by discarding null bytes in between good UTF8 characters.

I'm more fluent in PowerShell, so here's what I wrote to prove that this will work.

$progressCounter = 0.0
$progressScaleString = "0%-----------25%-----------50%-----------75%-----------100%"
$psi = new-object system.diagnostics.processstartinfo
$psi.FileName = "C:\Program Files (x86)\Illustrate\dBpoweramp\CoreConverter.exe"
# Moby Dick audiobook available at <http://ia600208.us.archive.org/0/items/moby_dick_librivox/mobydick_135_melville.mp3>
$psi.arguments =  '-infile="C:\AudioBooks\mobydick_135_melville.mp3" -outfile="c:\AudioBooks\mobydick_135_melville.flac" -convert_to="flac" -encoding="SLOW"'
$psi.StandardOutputEncoding = [System.Text.Encoding]::Unicode
$psi.RedirectStandardOutput = $true
$psi.UseShellExecute = $false
$proc = new-object System.Diagnostics.Process
$proc.StartInfo = $psi
$proc.Start();
#Look for the magic progress bar string
$outputBuf = ""
while($true){ $chr = [char]$proc.StandardOutput.BaseStream.ReadByte(); if($chr -ne [char]0){ $outputBuf += $chr; } if($outputBuf.Contains($progressScaleString)){ break; }else{ sleep .01; }}
#We've seen the progress ruler, now start counting the pips.
while($progressCounter -le 100.0){ $chr = $proc.StandardOutput.BaseStream.ReadByte(); if($chr -lt 0){break;} if([char]$chr -eq [char]"*"){ $progressCounter += 100.0/($progressScaleString.Length+1); write-host $progressCounter; }}

Here's my crack at porting this to VB; Just run it on a worker thread and hook PercentDone up to your UI:

Public Event PercentDone(ByVal Percent As Float)

Private Shared CoreConverter As New Process()

Private Shared CoreConverter_Info As New ProcessStartInfo() With { _
              .CreateNoWindow = True, _
              .UseShellExecute = False, _
              .RedirectStandardOutput = True, _
              .RedirectStandardError = True _
}

Private Shared Sub Run_CoreConverter()

    Dim ProgressScaleString As String = "0%-----------25%-----------50%-----------75%-----------100%"
    Dim ProgressCounter As Float = 0.0

    CoreConverter_Info.FileName = "C:\CoreConverter.exe"
    CoreConverter_Info.Arguments = String.Format("-infile=""{0}"" -outfile=""{1}"" -convert_to=""mp3 (Lame)""" ..., blah blah blah)
    CoreConverter_Info.StandardErrorEncoding = System.Text.Encoding.Unicode
    CoreConverter_Info.StandardOutputEncoding = System.Text.Encoding.Unicode
    CoreConverter.StartInfo = CoreConverter_Info
    CoreConverter.Start()

    Dim OutputBuf As String = ""
    Dim chr As Byte;
    While True
      chr = CoreConverter.StandardOutput.BaseStream.ReadByte();
      If chr < 0 Then
        Exit While
      ElseIf chr <> 0
        OutputBuf += CType(chr, Char)
      End If
      If OutputBuf.Contains(ProgressScaleString) Then
        Exit While
      Else
        System.Threading.Thread.Sleep(10)
      End If
    End While

    While ProgressCounter <= 100
      chr = CoreConverter.StandardOutput.BaseStream.ReadByte()
      If chr <= 0 Then
        Exit While
      End If
      If chr == CType("*"C, Char) Then
        ProgressCounter += 100.0/($progressScaleString.Length+1)
        RaiseEvent PercentDone(ProgressCounter)
      End If
    End While

End Sub

这篇关于运行一个命令行程序,并得到输出而处理仍在运行?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆