要为文本创建一个循环缓冲区,我会使用 a StringBuilder
,其容量设置为我想要显示的数据量的两倍左右。
const int DisplaySize = 10000;
StringBuilder fifo = new StringBuilder(2 * DisplaySize);
string AppendToFifo( string s )
{
if (s.Length >= DisplaySize) {
// FACT: the display will only include data from s
// therefore, toss the entire buffer, and only keep the tail of s
fifo.Clear();
fifo.Append(s, s.Length - DisplaySize, DisplaySize);
return fifo.ToString();
}
if (fifo.Length + s.Length > fifo.Capacity) {
// FACT: we will overflow the fifo
// therefore, keep only data in the fifo that remains on the display
fifo.Remove(0, fifo.Length + s.Length - DisplaySize);
}
fifo.Append(s);
if (fifo.Length <= DisplaySize) {
// FACT: the entire fifo content fits on the display
// therefore, send it all
return fifo.ToString();
}
// FACT: the fifo content exceed the display size
// therefore, extract just the tail
return fifo.ToString(fifo.Length - DisplaySize, DisplaySize);
}
当所有 if 条件都不为真时,快速路径会避免所有不必要的副本(在字符串不可变的 .NET 世界中,无法避免创建输出字符串的最终副本)。在其他情况下,只复制需要的字符。增加缓冲区的容量将提高快速路径的利用率。我一直小心避免做的是使用保留在显示器上的旧内容创建一个字符串对象,除了与新内容连接之外没有其他目的,并且立即变成垃圾。
显然,如果您使用 p/invoke 传递指向 StringBuffer 内容的指针而不是复制出子字符串,那将更加有效。