Как сохранить результаты STDOUT в текстовый файл? - PullRequest
4 голосов
/ 14 декабря 2010

У меня есть программа, которая использует сторонний инструмент командной строки для создания журналов. Сторонний поставщик генерирует весь свой вывод в STDOUT, который затем пользователь должен использовать команду " > test.txt" для сохранения файла.

Однако программа каким-то образом генерирует определенный объем созданного отчета, но не весь отчет. Это было проверено с помощью команды

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

в консоли командной строки, которая работает, и в программе, которая работает только частично.

Ошибки были сужены либо до ошибки аргументов, либо до части ошибки сохранения файла (streamReader). Следовательно, ошибка может быть связана с неправильным сохранением STDOUT.

Поэтому, может, кто-нибудь посоветует, пожалуйста, коды? Спасибо!

Аргументы для стороннего инструмента (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

Коды:

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

    }

Ответы [ 4 ]

5 голосов
/ 14 декабря 2010

Вы ждете завершения дочернего процесса? Похоже, вы начинаете читать его вывод слишком рано. Это можно сделать так:

process.Start();
process.WaitForExit();

Кроме того, вы можете начать получать вывод через делегатов до его завершения. Вот так (делегат вызывается для каждой строки текста):

process.OutputDataReceived += delegate(object sender, DataReceivedEventArgs e)
{
    // Store e.Data somewhere.
};
3 голосов
/ 14 декабря 2010

.NET может информировать вас о завершении процесса, а затем читать вывод.Потому что, как было сказано в его ответе + комментарии, если вы вызовете reader.ReadToEnd() до его завершения, вы не получите весь вывод.Если вы думаете об этом, это совершенно очевидно - данные еще не созданы, так как вы можете ожидать, что читатель их прочитает?

Используя события, вы не заблокируете метод, запускающий поток, которыйможет быть весьма полезным, если у вас есть приложение с графическим интерфейсом и вы не хотите останавливать пользовательский интерфейс во время работы дочернего процесса.

// tell it to raise events and hook up a callback to when it completes
process.EnableRaisingEvents = true;
process.Exited += process_Exited;
process.Start();

Этот метод будет вызван после завершения процесса:

void process_Exited(object sender, EventArgs e)
{
    var process = (Process)sender;
    using (var f = File.CreateText(@"..."))
    {
        f.WriteLine(process.StandardOutput.ReadToEnd());
    }
}
2 голосов
/ 14 декабря 2010

Класс System.Console имеет метод SetOut, который должен делать то, что вам нужно.

Вы должны вызвать Console.SetOut(yourTextWriter) в начале выполнения вашей программы.

Просто добавьте это в первой строке программы:

Console.SetOut(File.CreateText(locationToSaveLogs));
0 голосов
/ 05 января 2016

Вам необходимо использовать событие OutputDataReceived.В этой статье MSDN объясняется, как это делается:

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

Внутри обработчика запишите вывод в файл, используя StreamWriter, например:

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