做一个文件修复函数,从文件名,查找字符,比对,再替换字符。但是在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;
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;
改为
Length(CmpStr)
指针在32位系统中占用的长度就是4
CmpStr 是数组,不是指针,俩回事
编译器在编译时候,就判断变量类型,将结果,也就是立即数4编译进指令。
Length(array)调用下面方法取动态数组长度procedure _DynArrayLength;
asm
TEST EAX,EAX
JZ @@skip
MOV EAX,[EAX-4] //数组头地址-4的地址中的内容(即动态数组长度)取出
@@skip:
end;
var
axt: array of byte;
P: PInteger;
begin
SetLength(axt, 20); P := PInteger(axt);
dec(P);
si := P^;
ShowMessage(IntToStr(P^));
end;
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;已经解决,结帖。
你可以看下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的第一个参数已经是个地址了,这里就会出错