Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Read 7Zip progress using from Process.StandardOuput

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: 7Zip shows progress in the output terminal

It then uses backspace chars to overwrite the previous progress.

7Zip updated progress in the output terminal

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 standard output redirection does not show progress characters overwritten with backspaces

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.

like image 217
Alexander Higgins Avatar asked Aug 04 '26 09:08

Alexander Higgins


1 Answers

Though the post had been months, in case your problem (not able to get progress from 7zip when execute in command line) still exists, use the "-bsp1" switch in command line argument.

I was also looking for the solution of same issue and just got it (tested successfully in my case) right. By redirect StandardOutput, repeatedly do cmd.StandardOutput.ReadLine() (the Synchronous method, I tested this method instead of asynchronous method that use EventHandler, but I think async method would work too), and use RegExp to detect the progress to update my UI.

My command (run in .NET)

C:\Program Files\7-Zip\7z.exe a -t7z -mx=9 -bsp1 "G:\Temp\My7zTest_Compressed.7z" "G:\SourceFolder"

Credit to @justintjacob How to show extraction progress of 7zip inside cmd?

like image 161
blackbox Avatar answered Aug 06 '26 01:08

blackbox



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!