做一个文件修复函数,从文件名,查找字符,比对,再替换字符。但是在ARRAY OF CHAR遇到问题,如果手动设置数组,READBUFFER可以读到数据,替换也正常。现在用动态数组做动态列表修复,但是SetLength(CmpStr,RepairStrLen)后,SIZEOF(CmpStr)值永远为4,而且读取不到数据。全部家当送上function TMainFrm.RepairStr(sFileName:String;FindStr:string;RepairStr:String;RepairStrLen:integer):Boolean;
var
  TmpMemoryStream : TMemoryStream;
  CmpStr        : array of Char;
  CmpStr1        : array of Char;
  FileSize,iAddress      : Integer;
  bWrite        : Boolean;
  s          : String;
  I        : Integer;
begin
  bWrite := False;
  Result := False;
  try
    TmpMemoryStream := TMemoryStream.Create;
    try
      TmpMemoryStream.Clear;
      TmpMemoryStream.LoadFromFile(sFileName);
      FileSize := TmpMemoryStream.Size;
      TmpMemoryStream.Position:=TmpMemoryStream.Size;
      TmpMemoryStream.Position:=0;
      SetLength(CmpStr,RepairStrLen);
      SetLength(CmpStr1,RepairStrLen);
      SetLength(s,FileSize);
      CopyMemory(@s[1],TmpMemoryStream.Memory,TmpMemoryStream.size);
      iAddress := Pos(FindStr,s) - 1;
      TmpMemoryStream.Seek(iAddress,0);
      TmpMemoryStream.ReadBuffer(CmpStr, SizeOf(CmpStr));
      TmpMemoryStream.Seek(iAddress,0);
      TmpMemoryStream.ReadBuffer(CmpStr1, SizeOf(CmpStr1));
      TmpMemoryStream.Seek(iAddress,0);
      For I := 0 to RepairStrLen do
      begin
        if CmpStr[I] <> RepairStr[I+1] then
          CmpStr[I] := RepairStr[I+1];
      end;
      if string(CmpStr) <> string(CmpStr1) then
      begin
        TmpMemoryStream.WriteBuffer(CmpStr, SizeOf(CmpStr));
        bWrite := True;
      end;
    Finally
      Result := True;
      if bWrite = True then
        TmpMemoryStream.SaveToFile(sFileName);
      TmpMemoryStream.Free;
    end;
  except
    TmpMemoryStream.Free;
    Result := False;
    exit;
  end;
end;

解决方案 »

  1.   

    SIZEOF(CmpStr)
    改为
    Length(CmpStr)
      

  2.   

    SIZEOF(CmpStr) 
    指针在32位系统中占用的长度就是4
      

  3.   


    CmpStr 是数组,不是指针,俩回事 
      

  4.   

    数组是可以SIZEOF的,我搞不明白为什么动态数组为什么不能SIZEOF
      

  5.   

    SizeOf(array)
    编译器在编译时候,就判断变量类型,将结果,也就是立即数4编译进指令。
    Length(array)调用下面方法取动态数组长度procedure   _DynArrayLength;   
      asm   
             TEST         EAX,EAX   
             JZ             @@skip   
             MOV           EAX,[EAX-4]   //数组头地址-4的地址中的内容(即动态数组长度)取出
      @@skip:   
      end;   
      

  6.   

    还有一种取动态数组长度的方法,这种更容易理解。
    var
        axt: array of byte;
        P: PInteger;
    begin
        SetLength(axt, 20);    P := PInteger(axt);
        dec(P);
        si := P^;
        ShowMessage(IntToStr(P^));
    end;
      

  7.   

    TmpMemoryStream.ReadBuffer(@CmpStr[1], Length(CmpStr));
      

  8.   

    这是无法使用指针啊。[Error] MainForm.pas(269): Constant object cannot be passed as var parameter
      

  9.   


    function TMainFrm.RepairStr(sFileName:String;FindStr:string;RepairStr:String;RepairStrLen:integer):Boolean;
    var
      TmpMemoryStream : TMemoryStream;
      CmpStr        : array of Char;
      CmpStr1        : array of Char;
      FileSize,iAddress,SizeOf1      : Integer;
      bWrite        : Boolean;
      s          : String;
      I        : Integer;
    begin
      bWrite := False;
      Result := False;
      SetLength(CmpStr,RepairStrLen);
      SetLength(CmpStr1,RepairStrLen);
      try
        TmpMemoryStream := TMemoryStream.Create;
        try
          TmpMemoryStream.Clear;
          TmpMemoryStream.LoadFromFile(sFileName);
          FileSize := TmpMemoryStream.Size;
          TmpMemoryStream.Position:=TmpMemoryStream.Size;
          TmpMemoryStream.Position:=0;
          SetLength(s,FileSize);
          CopyMemory(@s[1],TmpMemoryStream.Memory,TmpMemoryStream.size);
          iAddress := Pos(FindStr,s) - 1;
          if iAddress >= 0 then
          begin
            TmpMemoryStream.Seek(iAddress,0);
            TmpMemoryStream.ReadBuffer(CmpStr[0],Length(CmpStr));
            TmpMemoryStream.Seek(iAddress,0);
            TmpMemoryStream.ReadBuffer(CmpStr1[0],Length(CmpStr1));
            TmpMemoryStream.Seek(iAddress,0);
            For I := 0 to RepairStrLen - 1 do
            begin
              if CmpStr[I] <> RepairStr[I + 1] then
                CmpStr[I] := RepairStr[I + 1];
            end;
            if string(CmpStr) <> string(CmpStr1) then
            begin
              TmpMemoryStream.WriteBuffer(CmpStr[0], Length(CmpStr));
              bWrite := True;
            end;
          end;
        Finally
          Result := True;
          if bWrite = True then
            TmpMemoryStream.SaveToFile(sFileName);
          TmpMemoryStream.Free;
        end;
      except
        Result := False;
        exit;
      end;
    end;已经解决,结帖。
      

  10.   

    TmpMemoryStream.ReadBuffer(CmpStr[0], Length(CmpStr));
    你可以看下TCustomMemoryStream.Read的实现,最后调用的是Move(Pointer(Longint(FMemory) + FPosition)^, Buffer, Result);
    而move的实现procedure       Move( const Source; var Dest; count : Integer );
    {$IFDEF PUREPASCAL}
    var
      S, D: PChar;
      I: Integer;
    begin
      S := PChar(@Source);
      D := PChar(@Dest);
      if S = D then Exit;
      if Cardinal(D) > Cardinal(S) then
        for I := count-1 downto 0 do
          D[I] := S[I]
      else
        for I := 0 to count-1 do
          D[I] := S[I];
    end;
     注意D := PChar(@Dest);这句,move会自己去取地址,所以如果你送给ReadBuffer的第一个参数已经是个地址了,这里就会出错