I am trying to call rclone from my C# project using Process
, and also needs to get the live output from the process.
To achieve this, I am using the below code, found below:
It was taken from this post.
using System;
using System.IO;
namespace Collection_Manager
{
/// <summary>
/// Stream reader for StandardOutput and StandardError stream readers
/// Runs an eternal BeginRead loop on the underlaying stream bypassing the stream reader.
///
/// The TextReceived sends data received on the stream in non delimited chunks. Event subscriber can
/// then split on newline characters etc as desired.
/// </summary>
class AsyncStreamReader
{
public delegate void EventHandler<args>(object sender, string Data);
public event EventHandler<string> DataReceived;
protected readonly byte[] buffer = new byte[4096];
private StreamReader reader;
/// <summary>
/// If AsyncStreamReader is active
/// </summary>
public bool Active { get; private set; }
public void Start()
{
if (!Active)
{
Active = true;
BeginReadAsync();
}
}
public void Stop()
{
Active = false;
}
public AsyncStreamReader(StreamReader readerToBypass)
{
reader = readerToBypass;
Active = false;
}
protected void BeginReadAsync()
{
if (Active)
{
reader.BaseStream.BeginRead(buffer, 0, buffer.Length, new AsyncCallback(ReadCallback), null);
}
}
private void ReadCallback(IAsyncResult asyncResult)
{
int bytesRead = reader.BaseStream.EndRead(asyncResult);
string data = null;
//Terminate async processing if callback has no bytes
if (bytesRead > 0)
{
data = reader.CurrentEncoding.GetString(buffer, 0, bytesRead);
}
else
{
//callback without data - stop async
Active = false;
}
//Send data to event subscriber - null if no longer active
if (DataReceived != null)
{
DataReceived.Invoke(this, data);
}
//Wait for more data from stream
BeginReadAsync();
}
}
}
and I am calling this using this:
logHandler.writeLogToBuffer();
uploadProcess.StartInfo.UseShellExecute = false;
uploadProcess.StartInfo.CreateNoWindow = true; uploadProcess.StartInfo.RedirectStandardOutput = true;
uploadProcess.StartInfo.FileName = "rclone.exe";
uploadProcess.StartInfo.StandardOutputEncoding = Encoding.UTF8;
uploadProcess.StartInfo.Arguments =
"sync -P " +
"\"" + sourceDirectory + "\" " +
"\"" + Properties.Settings.Default.remoteName + "/" + destination + "\" " +
"--exclude '.*{/**,}' " +
"--config \"" + Properties.Settings.Default.rcloneConfig + "\" " +
Properties.Settings.Default.rcloneArgs;
uploadProcess.Start();
AsyncStreamReader stdOut = new AsyncStreamReader(uploadProcess.StandardOutput);
stdOut.DataReceived += (sender, data) =>
{
if (!string.IsNullOrEmpty(data))
{
if (data.Contains("ETA"))
{
logHandler.loadLogFromBuffer();
}
logHandler.writeToLog(data);
}
};
stdOut.Start();
However, the problem I'm having is that the first byte of the stream, (the T
from Transferring:...
message) is getting output separately from the rest of the stream.
The loghandler is just a method I wrote to write to a WPF richtextbox on the UI thread.
writeToLog(string message);
just appends a line to RTB, writeLogToBuffer();
writes the log to a buffer that can be loaded to load the RTB contents back with loadLogFromBuffer();
.
So, what is the problem here? Is this a rclone quirk? How do I go about solving this? Thanks in advance!