我正在尝试使用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写入文件,但这也不起作用。关于错误的标题格式或其他问题,我得到了一个不同的错误。
答案 0 :(得分:1)
好的!如果你不能击败他们,加入他们......
我找到了一个帖子,其中作者直接在Process StartInfo中管道传输文件,并宣称它有效。
http://weblogs.asp.net/israelio/archive/2004/08/31/223447.aspx
这对我来说没有用,正如另一位绅士的帖子中所述
他先用管道写一个批处理文件,然后执行它......
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;
}