2012-01-10 35 views
17

Tôi gặp sự cố trong dự án của mình. Tôi muốn khởi chạy một quá trình, 7z.exe (phiên bản console). Tôi đã thử ba thứ khác nhau:Nhận đầu ra trực tiếp từ Quy trình

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

Không có gì hoạt động. Nó luôn luôn "chờ đợi" cho đến cuối của quá trình để hiển thị những gì tôi muốn. Tôi không có bất kỳ mã nào để đặt, chỉ khi bạn muốn mã của tôi có một trong những thứ được liệt kê ở trên. Cảm ơn.

Edit: Mã của tôi:

 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); 
      } 
     } 

Hoặc

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); 
} 

Hoặc

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

đâu "quá trình" là quá trình trước khi thực hiện tôi

Ok tôi biết tại sao nó không hoạt động đúng: 7z.exe là lỗi: nó hiển thị một phần trăm tải trong giao diện điều khiển, và nó sẽ gửi thông tin chỉ khi tập tin hiện tại được hoàn thành. Trong khai thác ví dụ, nó hoạt động tốt :). Tôi sẽ tìm kiếm một cách khác để sử dụng 7z chức năng mà không cần 7z.exe (có thể với 7za.exe hoặc với một số DLL). Cảm ơn tất cả. Để trả lời câu hỏi, sự kiện OuputDataRecieved hoạt động tốt!

+0

lý do nào bạn không sử dụng DLL/SDK downloadabe từ 7zip cho phép kiểm soát tốt hơn nhiều so với bất kỳ kỹ thuật dựa trên bàn điều khiển nào? – Yahia

+0

Nó sẽ giúp xem mã mà bạn đã thử với Quy trình ví dụ bạn đang tạo Quy trình – MethodMan

+0

Vì 7z.exe bao gồm tất cả các chức năng tôi muốn. – Extaze

Trả lời

16

Hãy xem tại trang này, có vẻ đây là giải pháp cho bạn : http://msdn.microsoft.com/en-us/library/system.diagnostics.process.beginoutputreadline.aspxhttp://msdn.microsoft.com/en-us/library/system.diagnostics.process.standardoutput.aspx

[chỉnh sửa] Đây là một ví dụ làm việc:

 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: \ liệt kê tất cả các tệp từ thư mục gốc của C: đệ quy. Đây là rất nhiều tệp và tôi chắc chắn rằng nó không được thực hiện khi kết quả đầu tiên hiển thị trên màn hình. Có khả năng 7zip giữ đầu ra trước khi hiển thị nó. Tôi không chắc những gì bạn cung cấp cho các proces.

+0

Nhìn mã của tôi:/ – Extaze

+0

Tất cả những gì tôi có thể tìm thấy, là bạn nên sử dụng sự kiện OutputDataReceived, tại thời điểm này tôi không có thời gian để kiểm tra nó, có thể sau này. (http://harbertc.wordpress.com/2006/05/16/reading-text-from-a-process-executed-programmatically-in-c/) –

+0

Tôi đã thử mọi thứ, nhưng vấn đề là 7z.exe. Tôi đã quyết định lấy một thư viện 7z cho C# (SevenZipSharp) và vấn đề đã được giải quyết. Cảm ơn;) – Extaze

0

Hãy thử điều này.

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

Hãy để ở trên nằm trong thread.

Bây giờ để cập nhật đầu ra để giao diện người dùng, bạn có thể sử dụng một timer với hai dòng

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

này có thể giúp bạn

+1

Như fas như tôi có thể nhìn thấy, mã này cũng sẽ chờ đợi cho đến khi nó được thực hiện. Như đã nêu trong câu hỏi, anh ta không muốn đợi cho đến khi nó được thực hiện, nhưng muốn sống đầu ra –

+0

Như Michiel nói, đó là để có được đầu ra "cuối cùng" – Extaze

1

Tôi đã sử dụng lớp CmdProcessor được mô tả here trên một số dự án có nhiều thành công. Nó có vẻ hơi khó khăn lúc đầu nhưng rất dễ sử dụng.

+0

Không hoạt động ... Nó chờ quá trình dừng lại để hiển thị thông tin cho tôi ... – Extaze

4

Tôi không biết liệu có ai vẫn đang tìm giải pháp cho việc này hay không, nhưng nó đã xuất hiện nhiều lần vì tôi đang viết một công cụ trong Unity để hỗ trợ một số trò chơi và do khả năng tương tác giới hạn của một số hệ thống với mono (ví dụ như PIA để đọc văn bản từ Word), tôi thường phải viết các tệp thực thi OS (cụ thể là Windows, đôi khi MacOS) và khởi chạy chúng từ Process.Start().

Sự cố là khi bạn khởi chạy tệp thực thi như thế này, nó sẽ kích hoạt trong một chuỗi khác chặn ứng dụng chính của bạn, gây treo. Nếu bạn muốn cung cấp phản hồi hữu ích cho người dùng của mình trong thời gian này ngoài các biểu tượng quay được gợi lên bởi hệ điều hành tương ứng của bạn, thì bạn đã hơi say. Sử dụng luồng sẽ không hoạt động vì luồng vẫn bị chặn cho đến khi quá trình thực hiện kết thúc. Các giải pháp tôi đã nhấn vào, mà có thể có vẻ cực đoan đối với một số người nhưng tôi tìm thấy các công trình khá tốt đối với tôi, là sử dụng ổ cắm và đa luồng để thiết lập comms đồng bộ đáng tin cậy giữa hai ứng dụng. Điều này có nghĩa là: Tất nhiên, điều này chỉ hoạt động nếu bạn là tác giả của cả hai ứng dụng. Nếu không, tôi nghĩ bạn không may mắn. ... Tôi muốn xem liệu nó có hoạt động với đa luồng bằng cách sử dụng phương pháp truyền thống hay không, vì vậy nếu ai đó muốn thử điều đó và đăng kết quả ở đây sẽ thật tuyệt vời.

Dù sao, đây là giải pháp hiện đang làm việc cho tôi:

Trong ứng dụng chính, hoặc gọi điện thoại, tôi làm điều gì đó như thế này:

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

Đây là nơi tôi thiết lập máy chủ 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; 
} 

Đây là trình xử lý socket của tôi cho chuỗi ... lưu ý rằng bạn sẽ phải tạo nhiều luồng trong một số trường hợp; đó là lý do tại sao tôi có mà _builderCommThreads Danh sách trong đó (tôi chuyển nó từ mã ở nơi khác, nơi tôi đang làm một cái gì đó tương tự nhưng gọi nhiều trường hợp liên tiếp):

/// <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; 
} 

Tất nhiên, bạn sẽ cần phải khai báo một số nội dung lên ở đầu trang:

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

... sau đó trong thực thi gọi, thiết lập đầu kia (tôi đã sử dụng tĩnh trong trường hợp này, bạn có thể sử dụng những gì mà bạn muốn):

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); 
    } 
} 

. ..TÔI' m bằng cách sử dụng công cụ này để khởi chạy công cụ dòng lệnh trên Windows sử dụng công cụ PIA để kéo văn bản ra khỏi tài liệu Word. Tôi đã thử PIA các .dll trong Unity, nhưng chạy vào các vấn đề interop với mono. Tôi cũng đang sử dụng nó trên MacOS để gọi các kịch bản lệnh shell khởi chạy các cá thể Unity bổ sung trong batchmode và chạy các kịch bản trình soạn thảo trong các trường hợp đó nói lại công cụ trên kết nối socket này. Thật tuyệt vời, bởi vì bây giờ tôi có thể gửi phản hồi cho người dùng, gỡ lỗi, theo dõi và phản hồi các bước cụ thể trong quy trình, v.v. v.v.

HTH

4

Để xử lý chính xác đầu ra và/hoặc chuyển hướng lỗi, bạn cũng phải chuyển hướng đầu vào. Dường như tính năng/lỗi trong thời gian chạy của ứng dụng bên ngoài mà bạn đang bắt đầu và từ những gì tôi đã thấy cho đến nay, nó không được đề cập đến bất cứ nơi nào khác.

sử dụng Ví dụ:

 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

Việc chuyển hướng đầu vào tiêu chuẩn đã khắc phục sự cố cho tôi. –

Các vấn đề liên quan