如何在TMemoryStream中的索引处插入字符串?

时间:2013-11-21 15:50:11

标签: delphi delphi-xe4

如何在TMemoryStream的指定索引处插入字符串?如果你添加了一个字符串 “a”到索引0处的现有字符串“b”,它将向前移动“ab”等。例如,这是TStringBuilder.Insert所做的。

2 个答案:

答案 0 :(得分:3)

  1. 展开流,以便有空间插入文本。因此,如果要插入的文本的长度为N,则需要使流N字节更大。
  2. 从插入点开始,将所有现有内容复制到右侧,以便为插入腾出空间。致电Move即可完成此操作。您将把这个文本N字节移到右边。
  3. 在插入点处写入插入的字符串。
  4. 我假设是8位编码。如果使用16位编码,那么流需要增加2N个字节,依此类推。

    您会发现这是一项潜在的昂贵操作。如果您关心表现,您将尽一切可能避免不必这样做。

    P.S。如果我冒犯了任何从右到左的语言读者,我以英格兰为中心假设字符串从左向右运行,我很抱歉!


    你问了一些代码。这是:

    procedure TMyStringBuilder.Insert(Index: Integer; const Str: string);
    var
      N: Integer;
      P: Char;
    begin
      N := Length(Str);
      if N=0 then
        exit;
      FStream.Size := FStream.Size + N*SizeOf(Char);
      P := PChar(FStream.Memory);      
      Move((P + Index)^, (P + Index + N)^, (FStream.Size - N - Index)*SizeOf(Char));
      Move(Pointer(Str)^, (P + Index)^, N*SizeOf(Char));
    end;
    

    请注意,我编写了此代码,然后查看了TStringBuilder中的代码。它几乎完全相同!


    您最终为此操作编写的代码与TStringBuilder中的代码相同,这一事实应该会导致您停下来思考。您正在构建的这个新的字符串构建器替换类很可能最终具有与原始相同的实现。你的替换品很可能不会比原版更好,而且更换的性能会更差。

    对我来说看起来有点像过早地进行优化一样。根据您在下面的评论,您还没有计算代码来证明在TStringBuilder方法中花费的时间是您的瓶颈。这真的是你需要做的第一件事。

    假设您执行此计时并证明TStringBuilder方法是您的瓶颈,那么您需要确定该代码执行低于标准的原因。然后你需要弄清楚如何改进代码。简单地重复原始课程的实施不会带来任何好处。

答案 1 :(得分:0)

要移动现有数据以便为新字符串数据腾出空间,可以使用指针操作和Move过程来加快操作速度。但只有插入索引低于原始流的大小时才需要完成。如果索引大于流大小,那么您可以:(1)扩展流大小以容纳索引号并用零值或空格填充额外的空间,或(2)将索引值减小到流大小,因此string将被插入或附加在流的末尾。

根据您的需要,您可以:(1)创建一个派生自TMemoryStream的类,或者(2)创建一个函数来处理TMemoryStream的实例。这是第一种情况:

type
  TExtMemoryStream = class(TMemoryStream)
  public
    procedure InsertString(Index: Integer; const S: string);
  end;

procedure TExtMemoryStream.InsertString(Index: Integer; const S: string);
var
  SLength, OldSize: Integer;
  Src, Dst, PointerToS: ^Char;
begin
  if Index > Size then Index := Size;
  SLength := Length(S);
  OldSize := Size;
  SetSize(Size + SLength);
  Src := Memory; Inc(Src, Index);
  Dst := Src; Inc(Dst, SLength);
  Move(Src^, Dst^, OldSize - Index);
  PointerToS := @S[1];
  Move(PointerToS^, Src^, SLength);
end;

或第二种情况:

procedure InsertStringToMemoryStream(MS: TMemoryStream;
  Index: Integer; const S: string);
var
  SLength, OldSize: Integer;
  Src, Dst, PointerToS: ^Char;
begin
  if Index > MS.Size then Index := MS.Size;
  SLength := Length(S);
  OldSize := MS.Size;
  MS.SetSize(MS.Size + SLength);
  Src := MS.Memory; Inc(Src, Index);
  Dst := Src; Inc(Dst, SLength);
  Move(Src^, Dst^, OldSize - Index);
  PointerToS := @S[1];
  Move(PointerToS^, Src^, SLength);
end;

在那里,希望它有所帮助:)