I have a program which utilizes a 3rd party command line tool to generate logs. The 3rd party generates all its output to the STDOUT which the user must then use the " > test.txt"
command to save the file.
However the program somehow generates a certain amount of report generated but not the entire report. This was test by using the command
C:\Test\ftk\ripxp>ripxp.exe -r C:\test\ftk\ntuser.dat -d "C:\System Volume\_rest
ore{BB12863B-2C77-46C9-BCDA-1810E52F1089}" -p runmru > C:\test\test05.txt
on the command line console which works and on the program which works only partially.
The errors were narrowed down to either the arguments error or the file saving error part (streamReader). Therefore the error could be due to the STDOUT not being properly saved.
Therefore may someone please advise on the codes? Thanks!
The Arguments for the 3rd party tool(2008 H. Carvey):
RipXP v.20081001 - CLI RegRipper tool
RipXP [-r Reg hive file] [-p plugin module][-d RP dir][-lgh]
Parse Windows Registry files, using either a single module from the plugins folder.
Then parse all corresponding hive files from the XP Restore Points (extracted from
image) using the same plugin.
-r Reg hive file...Registry hive file to parse
-g ................Guess the hive file (experimental)
-d RP directory....Path to the Restore Point directory
-p plugin module...use only this module
-l ................list all plugins
-h.................Help (print this information)
Ex: C:\>rip -g
C:\>rip -r d:\cases\ntuser.dat -d d:\cases\svi -p userassist
All output goes to STDOUT; use redirection (ie, > or >>) to output to a file.
copyright 2008 H. Carvey
The Codes:
static void Main(string[] args)
{
// Automatically finds folder that starts with _restore
DirectoryInfo directoryInfo = new DirectoryInfo(@"C:\System Volume\");
DirectoryInfo restoreFolder = directoryInfo.GetDirectories().FirstOrDefault(d => d.Name.StartsWith("_restore"));
// Gets the folder name
String baka = restoreFolder.Name;
if (restoreFolder == null)
throw new DirectoryNotFoundException();
Process process = new Process();
process.Sta开发者_StackOverflow中文版rtInfo.FileName = @"C:\test\ftk\ripxp\ripxp.exe";
process.StartInfo.Arguments = @"-r C:\test\ftk\ntuser.dat -d C:\System Volume\" + restoreFolder.Name + " -p runmru";
process.StartInfo.CreateNoWindow = false;
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardInput = true;
process.StartInfo.RedirectStandardError = true;
process.Start();
String text = @"-r C:\test\ftk\ntuser.dat -d C:\System Volume\" +restoreFolder.Name + " -p runmru";
Console.WriteLine(baka);
Console.WriteLine(text);
// Strangely the program only outputs the first section "-r C:\test\ftk\ntuser.dat" argument results.....
System.IO.StreamReader reader = process.StandardOutput;
String sRes = reader.ReadToEnd();
StreamWriter SW;
SW = File.CreateText(@"C:\test\test01.txt");
SW.WriteLine(sRes);
SW.Close();
Console.WriteLine("File Created Successfully");
reader.Close();
}
Are you waiting for the child process to finish? It looks like you start reading its output too early. It could be done like this:
process.Start();
process.WaitForExit();
Also, you can start receiving the output via delegates before it finishes. Like this (the delegate is called for each line of text):
process.OutputDataReceived += delegate(object sender, DataReceivedEventArgs e)
{
// Store e.Data somewhere.
};
You can have .NET inform you when the process has exited and then read the output. Because, as detunized mentioned in his answer+comment, if you call reader.ReadToEnd()
before it has completed, you won't get all the output. If you think of it, it's quite obvious - the data hasn't been produced yet, so how can you expect the reader to read it?
By using events you will not block the method that starts the thread which can be quite useful if you have a GUI application and don't want to freeze the user interface while the child process is running.
// tell it to raise events and hook up a callback to when it completes
process.EnableRaisingEvents = true;
process.Exited += process_Exited;
process.Start();
This method will be called when the process has completed:
void process_Exited(object sender, EventArgs e)
{
var process = (Process)sender;
using (var f = File.CreateText(@"..."))
{
f.WriteLine(process.StandardOutput.ReadToEnd());
}
}
The System.Console class has a SetOut
method that should do what you need.
You should call Console.SetOut(yourTextWriter)
at the beginning of your program's execution.
Just add this at the first line of the program:
Console.SetOut(File.CreateText(locationToSaveLogs));
You need to use the OutputDataReceived event. This MSDN article explains how this is done:
https://msdn.microsoft.com/en-us/library/system.diagnostics.process.outputdatareceived(v=vs.110).aspx?cs-save-lang=1&cs-lang=csharp#code-snippet-2
Inside of the handler write the output to a file using the StreamWriter like:
StreamWriter sw = new StreamWriter(sOutputFilePath);
Process process = new Process();
process.StartInfo.FileName = "ipconfig.exe";
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
process.OutputDataReceived += new DataReceivedEventHandler((sender, e) =>
{
if (!String.IsNullOrEmpty(e.Data))
{
sw.WriteLine(e.Data);
}
});
process.Start();
process.BeginOutputReadLine();
process.WaitForExit();
sw.Close();
精彩评论