Delphi中使用Ini文件是非常方便的,很简单的就可以操作一个Ini文件。但是也存在着局限性,比如TIniFile的ReadString函数最大只能读2047个字符,超过了的则读不出来,鉴于这个,很容易的修改,可以找到其ReadString函数,扩大其缓冲区则可。同时还有一点不足之处就是,不能写入流。写入流有的时候,用处也是非常大的了。但是Ini文件却没有提供该函数,进日由于工作中需要用到这样的东西,于是想了一个办法能够在Ini文件中读写流数据。其实写入流数据也是输入字符串。Ini文件中输入的字符串不能换行,否则换行后的字符串则成一个非有效的值了。所以,把流数据当字符串输入的时候,就要防止其有换行符号,于是想到一个办法,先把他变成16进制字符串,然后在写入这样就防止了换行。读出来,也就把16进制字符串再转换成二进制数据。
所以就需要如下几个函数了:
Function StreamToStr(Value: TStream): String; //流转化成16进制字符串
Function StrToStream(Const aStr: String; Value: TStream): Integer;//16进制字符串化为流数据
Function ReadStream(Const Section,aParamName: String; aValue: TStream): Integer;//读取流
Procedure WriteStream(Const Section,aParamName: String; aValue: TStream);//写入流
//*************************************************************
// 功能:指针区信息转16进制
// 参数: Ptr指定指针,Len指定取得的数据长度
//*************************************************************
function PointToHex(Const Ptr: pointer;Const Len: integer): string;
asm
Push ebx
push esi
push edi
test eax,eax
jz @@Exit
mov edi,eax
mov esi,ecx
mov ecx,edx
push ecx
add edx,edx
mov eax,esi
call System.@LStrSetLength //设置新串长度
mov eax,esi //新字符串地址
Call UniqueString //产生一个唯一的新字符串,串位置在eax中
pop ecx
@@SetHex:
xor edx,edx //清空edx
mov dl, [edi] //Str字符串字符
mov ebx,edx //保存当前的字符
shr edx,4 //右移4字节,得到高8位
mov dl,byte ptr[edx+@@HexChar] //转换成字符
mov [eax],dl //将字符串输入到新建串中存放
and ebx,$0F //获得低8位
mov dl,byte ptr[ebx+@@HexChar] //转换成字符
inc eax //移动一个字节,存放低位
mov [eax],dl
inc edi
inc eax
loop @@SetHex
@@Exit:
pop edi
pop esi
pop ebx
ret
@@HexChar: db '0123456789ABCDEF'
end;
//*************************************************************
// 名称: HexToBin
// 功能: 将16进制字符串转换成二进制信息存入
// 用法:
// Mem := TMemoryStream.Create;
// Mem.SetSize(100);
// str := 'TEST';
// writeSize := HeToBin(strToHex(Str),Mem.Memory,4);
//*************************************************************
function HexToBin(HexStr: string;BinnryBuf: pointer;BufSize: integer): integer;
asm
push ebx
push edi
Push ecx
mov edi,ecx
test eax,eax
Jz @@Exit
test edx,edx
Jz @@Exit
test ecx,ecx
Jz @@Exit
mov edi,[eax-4]
shr edi,1 //长度除2获得二进制实际长度
cmp edi,ecx //比较实际长度和给定长度
JB @@Belive //给定长度大于实际长度,直接执行,否则使用给定长度
mov edi,ecx //使用给定长度
@@Belive:
xor ecx,ecx
mov bh,[eax] //字符
cmp bh,'0' //查看是否在0到f之间的字符
JB @@Exit //小于0
cmp bh,'f'
JA @@Exit //大于f跳
sub bh,'0'
mov cl,bh
mov bh,byte ptr[ecx+@@Convert]
shl bh,4
xor ecx,ecx
inc eax //指针前移
mov bl,[eax]
cmp bl,'0' //查看是否在0到f之间的字符
JB @@Exit //小于0
cmp bl,'f'
JA @@Exit //大于f跳
sub bl,'0'
mov cl,bl
mov bl,byte ptr[ecx+@@Convert]
xor ecx,ecx
mov cl,bh
and ebx,00FFh
add ebx,ecx
mov [edx],ebx
inc eax
inc dx
dec edi
JNZ @@Belive
@@Exit:
Pop eax
sub eax,edi
pop edi
pop ebx
ret
@@Convert: //包含大小写的ABCDEF数组列
DB 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1
DB -1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1
DB -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
DB -1,10,11,12,13,14,15
end;
{通过上面的PointToHex函数将内存流转换位16进制字符串}
function TIniFile.StreamToStr(Value: TStream): String;
begin
result := PointToHex(TMemoryStream(Value).memory,Value.Size);
end;
{16进制串转换为流}
function TIniFile.StrToStream(const aStr: String; Value: TStream): Integer;
Var
Text: String;
Stream: TMemoryStream;
Pos: Integer;
Begin
Text := aStr;
If Text <> '' Then
Begin
If Value Is TMemoryStream Then
Stream := TMemoryStream(Value)
Else
Stream := TMemoryStream.Create;
Try
Pos := Stream.Position;
Stream.SetSize(Stream.Size + Length(Text) Div 2);
HexToBin(Text, Pointer(Integer(Stream.Memory) + Stream.Position), Length(Text) Div 2);
Stream.Position := Pos;
If Value <> Stream Then Value.CopyFrom(Stream, Length(Text) Div 2);
Result := Stream.Size - Pos;
Finally
If Value <> Stream Then Stream.Free;
End;
End
Else
Result := 0;
end;
{读取流数据}
function TIniFile.ReadStream(const Section, aParamName: String;
aValue: TStream): Integer;
Var
mValue: String;
begin
mValue := ReadString(Section,aParamName, '');
Result := StrToStream(mValue, aValue);
end;
{写入流数据}
procedure TIniFile.WriteStream(const Section, aParamName: String;
aValue: TStream);
Var
mValue: String;
Begin
mValue := StreamToStr(aValue);
WriteString(Section,aParamName, mValue);
end;