C#使用Process调用rclone获取实时输出时首字符单独输出问题
问题成因与解决方案
成因说明
该问题不是rclone的特性导致,是两个实现逻辑的叠加问题:
- 流读取本身存在天然分片特性:你所用的
AsyncStreamReader是直接从进程输出的基础流读取字节,操作系统、进程输出缓冲的机制本身不会保证一次性返回整行/整条消息的所有字节,首字母T刚好是第一次BeginRead返回的1个字节,剩余内容会在后续读取回调中返回,这是流读取的正常现象。 - 日志写入逻辑不合理:当前你拿到每一段分片数据就直接调用
writeToLog追加一行,自然会把单独的T当成一行输出,剩余内容被识别为下一行。
解决方案
方案1:AsyncStreamReader层面新增缓冲拼接(推荐)
修改AsyncStreamReader类,增加内部缓冲区暂存读取到的不完整内容,检测到完整行分隔符后再触发数据接收事件,修改后的核心代码如下:
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; private readonly StringBuilder _readBuffer = new StringBuilder(); // 新增内部缓冲字段 public bool Active { get; private set; } // 其他原有构造、Start、Stop、BeginReadAsync方法保持不变,仅修改ReadCallback private void ReadCallback(IAsyncResult asyncResult) { int bytesRead = reader.BaseStream.EndRead(asyncResult); if (bytesRead > 0) { string data = reader.CurrentEncoding.GetString(buffer, 0, bytesRead); _readBuffer.Append(data); // 拆分所有完整行输出 while (true) { int newlineIndex = _readBuffer.ToString().IndexOfAny(new[] { '\r', '\n' }); if (newlineIndex < 0) break; // 没有完整行,等待后续读取 string completeLine = _readBuffer.ToString(0, newlineIndex).TrimEnd('\r'); _readBuffer.Remove(0, newlineIndex + 1); if (!string.IsNullOrEmpty(completeLine) && DataReceived != null) { DataReceived.Invoke(this, completeLine); } } } else { Active = false; // 进程退出后输出缓冲中剩余的内容 if (_readBuffer.Length > 0 && DataReceived != null) { DataReceived.Invoke(this, _readBuffer.ToString().TrimEnd('\r', '\n')); _readBuffer.Clear(); } } if (Active) { BeginReadAsync(); } } // 其他原有代码保持不变 }
修改后你的事件订阅逻辑不需要做任何改动,就能收到完整的行内容。
方案2:适配rclone输出特性
你用了-P参数开启实时进度显示,rclone默认用回车符\r重写同一行更新进度,你可以在启动参数中添加--stats-one-line简化进度输出,或者替换-P为-v输出结构化日志,避免单行反复刷新带来的内容拆分问题。
内容的提问来源于stack exchange,提问作者Min Gu Kang
相关产品推荐
相关产品推荐

