Stdout процесса отличается в консоли от перенаправления - PullRequest
0 голосов
/ 28 июня 2018

Из приложения Windows C # мы хотим запустить cipher.exe, чтобы удалить данные из неиспользуемого дискового пространства, в данном случае диск D:

cipher.exe /w:D:\

Когда это делается из командной строки Windows, вывод будет:

To remove as much data as possible, please close all other applications while
running CIPHER /W.
Writing 0x00
...................................................................................................
Writing 0xFF
...................................................................................................
Writing Random Numbers
...................................................................................................

Эти строки с точками заполняются постепенно в течение всей процедуры шифрования. Мы думали, что будем читать эти точки из приложения C #, чтобы отслеживать прогресс и отображать его на индикаторе выполнения. Однако мы заметили, что когда стандартный вывод захвачен или перенаправлен, порядок отличается:

cipher.exe /w:D:\ > out.txt

В результате получается файл со следующим содержимым:

To remove as much data as possible, please close all other applications while
running CIPHER /W.
Writing 0x00
Writing 0xFF
Writing Random Numbers
...................................................................................................
...................................................................................................
...................................................................................................

И поэтому, когда мы пытаемся захватить это из приложения C #, мы не читаем точки до самого конца процесса. Например, при использовании следующего кода:

private void RunCipher()
{
    using (Process cipherProcess = new Process())
    {
        try
        {
            // Cipher does three phases, one with 00s, one with FFs and one with random bits
            // We count dots in the output for each phase to track the progress
            // The amount of dots per phase is always 99 (independent of the volume size)
            // See the end of this file to find the expected output

            cipherProcess.StartInfo.FileName = "cipher.exe";
            cipherProcess.StartInfo.Arguments = @"/w:D:\";

            cipherProcess.StartInfo.RedirectStandardOutput = true;
            cipherProcess.StartInfo.RedirectStandardError = true;
            cipherProcess.StartInfo.RedirectStandardInput = true;
            cipherProcess.StartInfo.UseShellExecute = false;
            cipherProcess.StartInfo.CreateNoWindow = true;

            cipherProcess.OutputDataReceived += CipherProcess_OutputDataReceived;
            cipherProcess.ErrorDataReceived += CipherProcess_ErrorDataReceived;
            cipherProcess.Exited += CipherProcess_Exited;

            cipherProcess.Start();

            cipherProcess.BeginOutputReadLine();
            cipherProcess.BeginErrorReadLine();
            cipherProcess.WaitForExit();
        }
        catch
        {
            Console.WriteLine("Exception occured");
        }
    }
    Console.WriteLine("Fininshed");
}

private void CipherProcess_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
    Console.WriteLine("OutputDataReceived: " + e.Data);
}

private void CipherProcess_Exited(object sender, EventArgs e)
{
    Console.WriteLine("Exited");
}

private void CipherProcess_ErrorDataReceived(object sender, DataReceivedEventArgs e)
{
    Console.WriteLine("ErrorDataReceived: " + e.Data);
}

Вывод этого:

OutputDataReceived: To remove as much data as possible, please close all other applications while
OutputDataReceived: running CIPHER /W.
OutputDataReceived: Writing 0x00
The thread 0x41ac has exited with code 0 (0x0).
The thread 0x408c has exited with code 0 (0x0).
OutputDataReceived: Writing 0xFF
The thread 0x39e4 has exited with code 0 (0x0).
The thread 0x3e30 has exited with code 0 (0x0).
OutputDataReceived: Writing Random Numbers
The thread 0x34ac has exited with code 0 (0x0).
The thread 0x3960 has exited with code 0 (0x0).
OutputDataReceived: ...................................................................................................
OutputDataReceived: ...................................................................................................
OutputDataReceived: ...................................................................................................
ErrorDataReceived: 
OutputDataReceived: 
Fininshed

Мы также пытались без OutputDataReceived + BeginOutputReadLine и вместо этого использовать process.StandardOutput.Read (), но у него есть та же проблема: сначала он читает все три из вывода «Writing (..)»:

private void RunCipher2()
{
    using (Process cipherProcess = new Process())
    {
        try
        {
            cipherProcess.StartInfo.FileName = "cipher.exe";
            cipherProcess.StartInfo.Arguments = @"/w:D:\";

            cipherProcess.StartInfo.RedirectStandardOutput = true;
            cipherProcess.StartInfo.RedirectStandardError = true;
            cipherProcess.StartInfo.RedirectStandardInput = true;
            cipherProcess.StartInfo.UseShellExecute = false;
            cipherProcess.StartInfo.CreateNoWindow = true;

            cipherProcess.Start();

            while (!cipherProcess.StandardOutput.EndOfStream)
            {
                char nextChar = (char)cipherProcess.StandardOutput.Read();
                Console.Write(nextChar);
            }

            cipherProcess.WaitForExit();
        }
        catch
        {
            Console.WriteLine("Exception occured");
        }
    }
    Console.WriteLine("Fininshed");
}

И все же вывод в порядке, которого мы не ожидали:

To remove as much data as possible, please close all other applications while
running CIPHER /W.
Writing 0x00
Writing 0xFF
Writing Random Numbers
...................................................................................................
...................................................................................................
...................................................................................................
Fininshed

Мы уже нашли этот поток, но это решение требует перенаправленного вывода для первой работы: Считать Process StandardOutput до получения новой строки

Что здесь происходит? Есть ли способ сделать эту работу? Или отслеживать прогресс по-другому? Конечно, мы могли бы обнаружить сообщения «Написание» и сообщать о прогрессе в трети ... но кажется, что это должно быть возможно:)

1 Ответ

0 голосов
/ 28 июня 2018

Предполагая, что "..." появляется постепенно, по мере достижения прогресса, вам нужно вместо использования события DataRecpected захватить поток StandardOutput и фактически прочитать его по одному символу за раз. Таким образом, вы увидите каждую отдельную точку остановки, как она написана. Затем вы можете посчитать, сколько у вас было, и использовать это, чтобы сделать вывод о прогрессе.

...