I am redirecting Process.StandardOutput
and Process.StandardError
from a System.Diagnostics.Process
that uses 7zip to extract and zip archives and am unable to read the progress from the process.
It appears, 7Zip like some other applications, emit are backspace and delete characters to partially write a line data and then and delete the written characters using backspace and delete in order o show progress. I am trying to read those partial line outputs from the target process am unable to do so. However, I may be wrong in this assumption.
What I have tried:
var process = new Process
{
StartInfo =
{
FileName = command,
Arguments = arguments,
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true
}
};
process.Start();
After the above code block, I have tried using various methods of reading the data.
I have tried the async event handlers:
process.OutputDataReceived += (sender, args) => { Console.WriteLine(args.Data); };
process.ErrorDataReceived += (sender, args) => { Console.WriteLine(args.Data); };
process.BeginOutputReadLine();
process.BeginErrorReadLine();
I have tried using the async methods of the StandardOutput:
while (!process.StandardOutput.EndOfStream)
{
char[] buffer = new char[256];
int read = process.StandardOutput.ReadAsync(buffer, 0, buffer.Length).Result;
Console.Write(buffer, 0, read);
}
and
process.StandardOutput.BaseStream.CopyToAsync(Console.OpenStandardOutput());
And have tried using the async methods of the underlying base stream.
while (!process.StandardOutput.EndOfStream)
{
byte[] buffer = new byte[256];
int read = process.StandardOutput.BaseStream.ReadAsync(buffer, 0, buffer.Length).Result;
string data = Encoding.UTF8.GetString(buffer, 0, read);
Console.Write(data);
}
As an example, run 7Zip from the terminal with the following command:
"c:\program files\7-zip\7z.exe" x -o"C:\target" "K:\Disk_23339.secure.7z"
This shows progress output when running directly in a command prompt, with each success progress incrementing overwriting the previous:
It then uses backspace chars to overwrite the previous progress.
Running the same command and arguments using Process.Start()
var process = new Process
{
StartInfo =
{
FileName = "c:\program files\7-zip\7z.exe",
Arguments = 'x -o"C:\target" \"K:\Disk_23339.secure.7z\"",
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true
}
};
process.Start();
process.StandardOutput.BaseStream.CopyToAsync(Console.OpenStandardOutput());
process.WaitForExit();
When running this and attempting to read the redirected standard output of the process characters that are not emitted from the source process that do not contain a new line (either by linefeed or carriage return + line feed) are output to the standard output or standard error of System.Diagnostics.Process
and hence never written to the console.
7zip of course is just one example. This issue also occurs with numerous PowerShell and Python scripts.
Is there anyway to read these characters from Process.StandardOutput
and Process.StandardError
.
I am not sure but I think the issue is the underlying stream reader reads one line at a time and never returns these partial lines because they never include line ending characters.