在更新行而不是创建新行时重定向StandardOutput

时间:2013-08-23 20:01:01

标签: c# .net process progress redirectstandardoutput

我正在我的应用内发布rsync。现在它工作正常,它打开一个控制台窗口,提示我输入密码,并在文件复制时显示文件进度。

public static int SyncFolder(string sourceFolder, string destFolder)
{

    Process rsync = new Process();
    rsync.StartInfo.FileName = Path.Combine(RsyncPath, "rsync.exe");
    rsync.StartInfo.UseShellExecute = true;
    rsync.StartInfo.Arguments = String.Join(" ", new[] { "-rltzh --progress --chmod=a=rw,Da+x", FileUtils.EncodeParameterArgument(sourceFolder), FileUtils.EncodeParameterArgument(destFolder) });
    rsync.Start();
    rsync.WaitForExit();

    return rsync.ExitCode;
}

问题是我不希望打开单独的控制台窗口。我想在某种类型的控件中显示文本进度,并从程序本身内部响应任何提示(如输入密码)。

public int SyncFolder(string sourceFolder, string destFolder)
{

    Process rsync = new Process();
    rsync.StartInfo.FileName = Path.Combine(RsyncPath, "rsync.exe");
    rsync.StartInfo.UseShellExecute = false;
    rsync.StartInfo.RedirectStandardInput = true;
    rsync.StartInfo.RedirectStandardOutput = true;
    rsync.StartInfo.RedirectStandardError = true;
    rsync.StartInfo.Arguments = String.Join(" ", new[] { "-rltzh --progress --chmod=a=rw,Da+x", FileUtils.EncodeParameterArgument(sourceFolder), FileUtils.EncodeParameterArgument(destFolder) });

    rsync.ErrorDataReceived += rsync_ErrorDataReceived;
    rsync.OutputDataReceived += rsync_OutputDataReceived;

    rsync.Start();
    BindToUiConrol(rsync.StandardInput);

    rsync.WaitForExit();

    return rsync.ExitCode;
}

private void rsync_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
    //Magic!
}

private void rsync_ErrorDataReceived(object sender, DataReceivedEventArgs e)
{
    //Even more Magic!
}

private void BindToUiConrol(StreamWriter standardInput)
{
   if(this.InvokeRequired)
   {
       this.BeginInvoke(new Action<StreamWriter>(BindToUiConrol), standardInput);
       return;
   }

   //Hook up events here so a single line text box dumps it's text in when you hit enter.
}

这就是我被困的地方。如果我没有在同一行上继续更新的%',我会让它在进入时继续转储新行,但是如何处理重新使用的行并将新值放入其中?

我的梦想解决方案是在表单中嵌入一种控制台窗口,类似于HyperTerminal在旧版本的Windows中所做的,但我不知道在.NET中如何做到这一点。


以下是显示问题的示例程序

public class Program
{

    private static void Main(string[] args)
    {
        Console.Write("1");
        Console.WriteLine();

        Console.Write("2");
        Console.CursorLeft = 0;
        Console.Write("3");
        Console.WriteLine();

        Console.Write("4");
        Console.WriteLine();
    }
}

如何编写将显示

的Forms应用程序
1
3
4
运行过程后,在控件中

2 个答案:

答案 0 :(得分:1)

一般来说,这不是一个微不足道的问题。这与Windows / Console应用程序没有真正写入标准输出和标准错误这一事实有关,它们写入“控制台”。当您只关心所有文本和所有错误文本时,有各种各样的黑客和标准错误可以正常工作,但没有什么能够以交互方式正常工作,因为事物被缓冲了。

请按照此讨论获取更多信息:

Writing a console wrapper in C#?

答案 1 :(得分:-1)

您要做的是将终端文本附加到多行文本框或RichTextBox。

您还需要捕获该控件上的键盘事件。

您可能遇到的一个问题是程序输入和GUI在不同的线程上运行。

How to update textbox on GUI from another thread in C#

Fast Append Text to text box

原始问题澄清后 你要找的是检测回车的'\ r'字符,然后你需要回到文本框内容中的最后一个'\ n'换行符。

你可以通过多种方式做到这一点。

  1. 首先保留一个包含每一行的List,然后删除最后一行。并将文字附加在上一行之后。

  2. 您可以使用与文本框内容相匹配的Regex与文本框中的最终换行符。我相信正则表达式会"^.*\n" http://msdn.microsoft.com/en-us/library/system.text.regularexpressions.regex.aspx

  3. 只需将文本框内容截断为String.LastIndexOf('\n') http://msdn.microsoft.com/en-us/library/system.string.lastindexof.aspx

  4. 编辑#2:

    问题似乎是针对确定光标移动的触发因素 Microsoft在以下链接中提供了参考: http://msdn.microsoft.com/en-us/library/h21280bw.aspx

    您使用Console.Left = 0给出的第二个示例似乎抛出异常。由于这是对这个解决方案的一个人为的答案,我假设oyu真的只关心rsync,我敢冒险猜测只使用'\r''\n''\b'。唯一的另一个问题是它是否使用ANSI转义码http://en.wikipedia.org/wiki/ANSI_escape_code

    最后,循环必须读取输入并解析相应的字符。我建议使用BackgroundWorker,因为GUI将阻止等待循环。