读取System.Diagnostics.ProcessStartInfo标准输出为字节而不是字符

时间:2010-08-15 09:38:34

标签: c# .net svn

我正在尝试使用C#ProcessStartInfo自动化svnadmin转储。

我在命令行上完成它的方式是这样的,

svnadmin dump c:\Repositories\hackyhacky > c:\backup\hackyhacky.svn_dump

成功处理和转储,我可以通过将其恢复到另一个存储库来验证这一点

svnadmin load c:\Repositories\restore_test < c:\backup\hackyhacky.svn_dump

哪次成功恢复 - 耶!

现在......我需要使用C#将命令行管道复制到另一个文件中,但出于某种原因

var startInfo = new ProcessStartInfo(Path.Combine(SvnPath, "svnadmin"),"dump c:\Repositories\hackyhacky")
 {CreateNoWindow = true, RedirectStandardOutput = true,RedirectStandardError = true,UseShellExecute = false};
process.StartInfo = startInfo;
process.Start();
StreamReader reader = process.StandardOutput;
char[] standardOutputCharBuffer = new char[4096];
byte[] standardOutputByteBuffer;
int readChars = 0;
long totalReadBytes = 0;

// read from the StandardOutput, and write directly into another file

using (StreamWriter writer = new StreamWriter(@"C:\backup\hackyhacky.svn_dump", false)) {
    while (!reader.EndOfStream) {
       // read some chars from the standard out
       readChars = reader.Read(standardOutputCharBuffer, 0, standardOutputCharBuffer.Length);

       // convert the chars into bytes
       standardOutputByteBuffer = reader.CurrentEncoding.GetBytes(standardOutputCharBuffer);

       // write the bytes out into the file
       writer.Write(standardOutputCharBuffer.Take(readChars).ToArray());

       // increment the total read
       totalReadBytes += standardOutputByteBuffer.Length;
    }                    
}

将相同的回购转储到hackyhacky.svn_dump。

但是当我现在运行我的加载命令行时

svnadmin load c:\Repositories\restore_test < c:\backup\hackyhacky.svn_dump

我得到校验和错误很奇怪 - 错误!

svnadmin load c:\Repositories\restore_test < c:\backup\hackyhacky.svn_dump
< Started new transaction, based on original revision 1
     * adding path : Dependencies ... done.
     * adding path : Dependencies/BlogML.dll ...svnadmin: Checksum mismatch, fil
e '/Dependencies/BlogML.dll':
   expected:  d39863a4c14cf053d01f636002842bf9
     actual:  d19831be151d33650b3312a288aecadd

我猜这与我如何重定向和读取StandardOutput有关。

有没有人知道在C#中模仿命令行文件管道行为的正确方法?

非常感谢任何帮助。

-CV

更新

我尝试过使用BinaryWriter并使用standardOutputByteBuffer写入文件,但这也不起作用。关于错误的标题格式或其他问题,我得到了一个不同的错误。

3 个答案:

答案 0 :(得分:1)

好的!如果你不能击败他们,加入他们......

我找到了一个帖子,其中作者直接在Process StartInfo中管道传输文件,并宣称它有效。

http://weblogs.asp.net/israelio/archive/2004/08/31/223447.aspx

这对我来说没有用,正如另一位绅士的帖子中所述

http://webcache.googleusercontent.com/search?q=cache:http://www.deadbeef.com/index.php/redirecting_the_output_of_a_program_to_a

他先用管道写一个批处理文件,然后执行它......

amWriter bat = File.CreateText("foo.bat"); 
bat.WriteLine("@echo off"); 
bat.WriteLine("foo.exe -arg >" + dumpDir + "\\foo_arg.txt"); 
bat.Close(); 
Process task = new Process(); 
task.StartInfo.UseShellExecute = false; 
task.StartInfo.FileName = "foo.bat"; 
task.StartInfo.Arguments = ""; 
task.Start(); 
task.WaitForExit();

用他的话说:

  

真的很可怕,但它有   工作的好处!

坦率地说,我有点恼火,只要它已经占用了我,所以批处理文件解决方案效果很好,所以我会坚持下去。

答案 1 :(得分:0)

我要尝试的第一件事是将字符数组 - 而不是字节数组 - 写入文件。

只要输出只是简单的文本,这应该可以工作。但是,如果输出更复杂,还有其他编码问题:您将文件写为UTF-8,而命令行输出的默认值(我相信)是Windows-1252。

答案 2 :(得分:0)

我一直在努力做到这一点,只是偶然发现solution Hector Sosa's sourceforge项目使用的问题的另一个svnmanagerlib

  

解决这个问题的关键是围绕对WaitForExit()的调用   文件操作。还需要确保将输出写入磁盘。   以下是相关部分:

     

File.AppendAllText(destinationFile,myOutput.ReadToEnd());   svnCommand.WaitForExit(); File.AppendAllText(destinationFile,   myOutput.ReadToEnd());

     

请注意,我两次调用File.AppendAllText()。我已经找到   在第一次调用期间输出流不会写入所有内容   在某些情况下,到File.AppendAllText()。

public static bool ExecuteWritesToDiskSvnCommand(string command, string arguments, string destinationFile, out string errors)
        {
            bool retval = false;
            string errorLines = string.Empty;
            Process svnCommand = null;
            ProcessStartInfo psi = new ProcessStartInfo(command);

            psi.RedirectStandardOutput = true;
            psi.RedirectStandardError = true;
            psi.WindowStyle = ProcessWindowStyle.Hidden;
            psi.UseShellExecute = false;
            psi.CreateNoWindow = true;

            try
            {
                Process.Start(psi);
                psi.Arguments = arguments;
                svnCommand = Process.Start(psi);

                StreamReader myOutput = svnCommand.StandardOutput;
                StreamReader myErrors = svnCommand.StandardError;

                File.AppendAllText(destinationFile, myOutput.ReadToEnd());
                svnCommand.WaitForExit();
                File.AppendAllText(destinationFile, myOutput.ReadToEnd());

                if (svnCommand.HasExited)
                {
                    errorLines = myErrors.ReadToEnd();
                }

                // Check for errors
                if (errorLines.Trim().Length == 0)
                {
                    retval = true;
                }
            }
            catch (Exception ex)
            {
                string msg = ex.Message;
                errorLines += Environment.NewLine + msg;
            }
            finally
            {
                if (svnCommand != null)
                {
                    svnCommand.Close();
                }
            }

            errors = errorLines;

            return retval;
        }