2012-01-10 93 views
17

我的项目中存在问题。我想启动一个进程,7z.exe(控制台版本)。 我试过三种不同的东西:从流程获取实时输出

  • Process.StandardOutput.ReadToEnd();
  • OutputDataReceived & BeginOutputReadLine
  • 的StreamWriter

没有什么工作。它总是“等待”流程的结束,以显示我想要的。 我没有任何代码要放,只要你想要我的代码与上面列出的东西之一。谢谢。

编辑: 我的代码:

 process.StartInfo.UseShellExecute = false; 
     process.StartInfo.RedirectStandardOutput = true; 
     process.StartInfo.CreateNoWindow = true; 
     process.Start(); 

     this.sr = process.StandardOutput; 
     while (!sr.EndOfStream) 
     { 
      String s = sr.ReadLine(); 
      if (s != "") 
      { 
       System.Console.WriteLine(DateTime.Now + " - " + s); 
      } 
     } 

或者

process.StartInfo.UseShellExecute = false; 
process.StartInfo.RedirectStandardOutput = true; 
process.OutputDataReceived += new DataReceivedEventHandler(recieve); 
process.StartInfo.CreateNoWindow = true; 
process.Start(); 
process.BeginOutputReadLine(); 
process.WaitForExit(); 
public void recieve(object e, DataReceivedEventArgs outLine) 
{ 
    System.Console.WriteLine(DateTime.Now + " - " + outLine.Data); 
} 

或者

process.StartInfo.UseShellExecute = false; 
process.StartInfo.RedirectStandardOutput = true; 
process.Start(); 
string output = p.StandardOutput.ReadToEnd(); 
process.WaitForExit(); 

其中, “过程” 是我预先制作工艺

好吧,我知道为什么呢无法正常工作:7z.exe是错误:它在控制台中显示加载百分比,并且仅在当前文件完成时发送信息。在提取例如,它工作正常:)。我将搜索另一种使用7z函数而不使用7z.exe的方法(可能使用7za.exe或某些DLL)。谢谢大家。 要回答这个问题,OuputDataRecieved事件工作正常!

+0

任何你不使用7zip中的DLL/SDK downloadabe的原因,它允许比任何基于控制台的技术更好的控制吗? – Yahia 2012-01-10 18:44:39

+0

这将有助于查看您尝试使用的流程的代码,例如您在何处创建流程 – MethodMan 2012-01-10 18:56:40

+0

因为7z.exe涵盖了我想要的所有功能。 – Extaze 2012-01-10 20:22:21

回答

16

看看这个页面,看起来这是你的解决方案:http://msdn.microsoft.com/en-us/library/system.diagnostics.process.beginoutputreadline.aspxhttp://msdn.microsoft.com/en-us/library/system.diagnostics.process.standardoutput.aspx

[编辑] 这是一个工作示例:

 Process p = new Process(); 
     p.StartInfo.RedirectStandardError = true; 
     p.StartInfo.RedirectStandardOutput = true; 
     p.StartInfo.UseShellExecute = false; 
     p.StartInfo.CreateNoWindow = true; 
     p.StartInfo.FileName = @"C:\Program Files (x86)\gnuwin32\bin\ls.exe"; 
     p.StartInfo.Arguments = "-R C:\\"; 

     p.OutputDataReceived += new DataReceivedEventHandler(
      (s, e) => 
      { 
       Console.WriteLine(e.Data); 
      } 
     ); 
     p.ErrorDataReceived += new DataReceivedEventHandler((s, e) => { Console.WriteLine(e.Data); }); 

     p.Start(); 
     p.BeginOutputReadLine(); 

Btw,ls -R C:\递归列出C:根的所有文件。这些是很多文件,并且我确信在屏幕上显示第一个结果时它不会完成。 在显示它之前,7zip有可能保留输出。我不确定你给这个过程的参数。

+0

看我的代码:/ – Extaze 2012-01-10 20:50:59

+0

我所能找到的,是你应该使用的事件OutputDataReceived,目前我没有时间测试它,也许以后。 (http://harbertc.wordpress.com/2006/05/16/reading-text-from-a-process-executed-programmatically-in-c/) – 2012-01-11 18:50:29

+0

我试了一切,但问题是7z.exe。我决定为c#(SevenZipSharp)购买一个7z库,问题就解决了。谢谢;) – Extaze 2012-01-22 10:19:07

0

试试这个。

 Process notePad = new Process(); 

     notePad.StartInfo.FileName = "7z.exe"; 
     notePad.StartInfo.RedirectStandardOutput = true; 
     notePad.StartInfo.UseShellExecute = false; 

     notePad.Start(); 
     StreamReader s = notePad.StandardOutput; 



     String output= s.ReadToEnd(); 


     notePad.WaitForExit(); 

将上述设置为thread

现在用于更新输出到用户界面,你可以使用一个timer两条线

Console.Clear(); 
    Console.WriteLine(output); 

这可能会帮助你

+1

就像我看到的那样,这段代码也会等到它完成。正如问题所述,他不想等到它完成,但想要现场输出 – 2012-01-10 19:05:05

+0

正如Michiel所说,那是为了得到“最终”输出 – Extaze 2012-01-10 20:50:28

1

我在几个项目中使用了CmdProcessor类描述here,并取得了很大的成功。它看起来有点令人生畏,但使用起来非常简单。

+0

不起作用...它等待进程停止向我显示信息... – Extaze 2012-01-10 20:50:04

4

我不知道是否有人还在寻找一个解决方案,这一点,但它已经好几次对我来说,因为我支持的一些游戏,并且由于写在Unity的工具,以有限的互操作性与单某些系统(如PIA从Word中阅读文本,例如),我经常写OS专用(有时的Windows,MacOS的有时)的可执行文件,并从推出的Process.Start他们()。

的问题是,当你推出这样一个可执行它会在另一个线程块的主要的应用程序,从而导致挂起火起来。如果你想在这段时间内为你的用户提供有用的反馈信息,而不是由你的操作系统产生的旋转图标,那么你就有点被搞砸了。使用流将无法正常工作,因为线程在执行完成之前仍处于阻塞状态。

的解决方案,我已经打的,这可能看似极端的一些人,但我发现效果很好对我来说,就是用插座和多线程的两个应用程序之间建立可靠的通讯科同步。当然,这只适用于创作这两款应用的情况。如果没有,我认为你运气不好。 ...我想看看它是否适用于使用传统流式方法的多线程,因此如果有人想尝试并在此发布结果将会很棒。

总之,这里的当前工作为我的解决方案:

在主或调用的应用程序,我做这样的事情:

/// <summary> 
/// Handles the OK button click. 
/// </summary> 
private void HandleOKButtonClick() { 
string executableFolder = ""; 

#if UNITY_EDITOR 
executableFolder = Path.Combine(Application.dataPath, "../../../../build/Include/Executables"); 
#else 
executableFolder = Path.Combine(Application.dataPath, "Include/Executables"); 
#endif 

EstablishSocketServer(); 

var proc = new Process { 
    StartInfo = new ProcessStartInfo { 
     FileName = Path.Combine(executableFolder, "WordConverter.exe"), 
     Arguments = locationField.value + " " + _ipAddress.ToString() + " " + SOCKET_PORT.ToString(), 
     UseShellExecute = false, 
     RedirectStandardOutput = true, 
     CreateNoWindow = true 
    } 
}; 

proc.Start(); 

这里就是我建立socket服务器:

/// <summary> 
/// Establishes a socket server for communication with each chapter build script so we can get progress updates. 
/// </summary> 
private void EstablishSocketServer() { 
    //_dialog.SetMessage("Establishing socket connection for updates. \n"); 
    TearDownSocketServer(); 

    Thread currentThread; 

    _ipAddress = Dns.GetHostEntry(Dns.GetHostName()).AddressList[0]; 
    _listener = new TcpListener(_ipAddress, SOCKET_PORT); 
    _listener.Start(); 

    UnityEngine.Debug.Log("Server mounted, listening to port " + SOCKET_PORT); 

    _builderCommThreads = new List<Thread>(); 

    for (int i = 0; i < 1; i++) { 
     currentThread = new Thread(new ThreadStart(HandleIncomingSocketMessage)); 
     _builderCommThreads.Add(currentThread); 
     currentThread.Start(); 
    } 
} 

/// <summary> 
/// Tears down socket server. 
/// </summary> 
private void TearDownSocketServer() { 
    _builderCommThreads = null; 

    _ipAddress = null; 
    _listener = null; 
} 

这里是我的线插座处理器......注意,你必须创建在某些情况下,多线程;这就是为什么我有_builderCommThreads名单在那里(我把它移植从代码的其他地方,我在做类似的事情,但是打电话连续多个实例):

/// <summary> 
/// Handles the incoming socket message. 
/// </summary> 
private void HandleIncomingSocketMessage() { 
    if (_listener == null) return; 

    while (true) { 
     Socket soc = _listener.AcceptSocket(); 
     //soc.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 10000); 
     NetworkStream s = null; 
     StreamReader sr = null; 
     StreamWriter sw = null; 
     bool reading = true; 

     if (soc == null) break; 

     UnityEngine.Debug.Log("Connected: " + soc.RemoteEndPoint); 

     try { 
      s = new NetworkStream(soc); 
      sr = new StreamReader(s, Encoding.Unicode); 
      sw = new StreamWriter(s, Encoding.Unicode); 
      sw.AutoFlush = true; // enable automatic flushing 

      while (reading == true) { 
       string line = sr.ReadLine(); 

       if (line != null) { 
        //UnityEngine.Debug.Log("SOCKET MESSAGE: " + line); 
        UnityEngine.Debug.Log(line); 

        lock (_threadLock) { 
         // Do stuff with your messages here 
        } 
       } 
      } 

      // 
     } catch (Exception e) { 
      if (s != null) s.Close(); 
      if (soc != null) soc.Close(); 
      UnityEngine.Debug.Log(e.Message); 
      //return; 
     } finally { 

     // 
     if (s != null) s.Close(); 
     if (soc != null) soc.Close(); 

     UnityEngine.Debug.Log("Disconnected: " + soc.RemoteEndPoint); 
     } 
    } 

    return; 
} 

当然,你需要声明一些东西了顶部:

private TcpListener _listener = null; 
private IPAddress _ipAddress = null; 
private List<Thread> _builderCommThreads = null; 
private System.Object _threadLock = new System.Object(); 

...然后在调用的可执行文件,成立了另一端(我用静在这种情况下,你可以使用你想要什么都):

private static TcpClient _client = null; 
private static Stream _s = null; 
private static StreamReader _sr = null; 
private static StreamWriter _sw = null; 
private static string _ipAddress = ""; 
private static int _port = 0; 
private static System.Object _threadLock = new System.Object(); 

/// <summary> 
/// Main method. 
/// </summary> 
/// <param name="args"></param> 
static void Main(string[] args) { 
    try { 
     if (args.Length == 3) { 
      _ipAddress = args[1]; 
      _port = Convert.ToInt32(args[2]); 

      EstablishSocketClient(); 
     } 

     // Do stuff here 

     if (args.Length == 3) Cleanup(); 
    } catch (Exception exception) { 
     // Handle stuff here 
     if (args.Length == 3) Cleanup(); 
    } 
} 

/// <summary> 
/// Establishes the socket client. 
/// </summary> 
private static void EstablishSocketClient() { 
    _client = new TcpClient(_ipAddress, _port); 

    try { 
     _s = _client.GetStream(); 
     _sr = new StreamReader(_s, Encoding.Unicode); 
     _sw = new StreamWriter(_s, Encoding.Unicode); 
     _sw.AutoFlush = true; 
    } catch (Exception e) { 
     Cleanup(); 
    } 
} 

/// <summary> 
/// Clean up this instance. 
/// </summary> 
private static void Cleanup() { 
    _s.Close(); 
    _client.Close(); 

    _client = null; 
    _s = null; 
    _sr = null; 
    _sw = null; 
} 

/// <summary> 
/// Logs a message for output. 
/// </summary> 
/// <param name="message"></param> 
private static void Log(string message) { 
    if (_sw != null) { 
     _sw.WriteLine(message); 
    } else { 
     Console.Out.WriteLine(message); 
    } 
} 

。 ..一世' m使用它在Windows上启动一个命令行工具,该工具使用PIA将文本从Word文档中提取出来。我尝试了PIA Unity中的.dll,但遇到了单声道的互操作问题。我还在MacOS上使用它来调用shell脚本,这些脚本以batchmode方式启动其他Unity实例,并在那些通过此套接字连接与工具交谈的实例中运行编辑器脚本。这很好,因为我现在可以向用户发送反馈,调试,监视和响应该过程中的特定步骤等等。

HTH

4

要正确处理输出和/或错误重定向,还必须重定向输入。 它似乎是在开始的youre外部应用程序的运行时间,从我迄今所看到的特性/错误,它没有提到其他地方。

用法示例:

 Process p = new Process(...); 

     p.StartInfo.UseShellExecute = false; 
     p.StartInfo.RedirectStandardOutput = true; 
     p.StartInfo.RedirectStandardError = true; 
     p.StartInfo.RedirectStandardInput = true; // Is a MUST! 
     p.EnableRaisingEvents = true; 

     p.OutputDataReceived += OutputDataReceived; 
     p.ErrorDataReceived += ErrorDataReceived; 

     Process.Start(); 

     p.BeginOutputReadLine(); 
     p.BeginErrorReadLine(); 

     p.WaitForExit(); 

     p.OutputDataReceived -= OutputDataReceived; 
     p.ErrorDataReceived -= ErrorDataReceived; 

...

void OutputDataReceived(object sender, DataReceivedEventArgs e) 
    { 
     // Process line provided in e.Data 
    } 

    void ErrorDataReceived(object sender, DataReceivedEventArgs e) 
    { 
     // Process line provided in e.Data 
    } 
+1

标准输入的重定向为我解决了问题。 – 2016-02-01 10:15:31