To 楼主:
1、首先纠正您一个错误,string 是一种指针,它的大小固定是 4 个字节,因此您的 TRegStruc 记录大小也是固定的。
2、含有字符串和数字混合的文件,跟您用何种记录存储没有太大关系,应该解决的主要问题是如何进行文件存取操作。
3、第一步,应该设计文件的存储结构。既然又要写,又要读,那么您首先应该想到,如果读取记录的时候不知道文件中一共有多少记录那是多么可怕。因此文件头中至少要含有 4 个字节的空间,用于记录文件中含有的记录数。
4、第二步,因为 Name、Value 字段都是 string 类型,您应该想到存储在文件中的每个记录都应该加上一个 4 字节的字段,用于存储本条记录的大小,否则读取文件时无法判断每次应该读取多少字节才算是一条完整的记录。另外 Name、Value 相邻,并且都是字符串,它们之间至少应该用 0 隔开,否则你无法判断哪个属于 Name 哪个属于 Value。
文件的结构如下(注意文件结构跟您的 TRegStruc 记录毫无关系):
------------文件开头-------------
记录总数(4字节)
------------第一条记录-----------
本条记录大小(4字节)
KeyIndex(4字节)
KeyType(谁知道 TRegKeyType 多少狗屁字节,只有某人知道)
Action(同上)
Name(N 字节)
#0
Value(M 字节)
#0
------------第二条记录-----------
...
------------文件结尾-----------
5、200 分还算可以,楼主迫切想知道代码,给您写了一个。其实这类问题本没有难度,只是很多人拘泥于什么“二进制文件vs文本文件vs无类型文件”、“固定长度记录文件vs变长记录文件”,造成这个后果的罪魁祸首是 Delphi 中的所谓“类型文件”。其实文件本身没有区别,只是读取方式不同。
type
TRegStruc = record
KeyIndex: Integer;
KeyType: TRegKeyType;
Action: TActionType;
Name: string;
Value: string;
end;
TRegStrucs = array of TRegStruc;
const
//HEAD_SIZE 是 TRegStruc 中固定长度部分的大小
HEAD_SIZE: Integer = SizeOf(TRegStruc) - SizeOf(string)*2;
//RegStrucsNum 用于返回文件中含有的记录总数
//RegStrucsToRead 不用人工初始化,本过程会自动初始化
procedure ReadRegFile(const FileName: string
var RegStrucsToRead: TRegStrucs;
var RegStrucsNum: DWORD);
var
hFile: THandle;
n, r, i: DWORD;
buffer, p: PChar;
begin
hFile := CreateFile(PChar(FileName), GENERIC_READ, FILE_SHARE_READ, nil,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL or FILE_FLAG_SEQUENTIAL_SCAN, 0);
ReadFile(hFile, n, SizeOf
, r, nil);
RegStrucsNum := n;
SetLength(RegStrucsToRead, RegStrucsNum);
for i := 0 to RegStrucsNum - 1 do
begin
ReadFile(hFile, n, SizeOf
, r, nil);
Dec(n, SizeOf
);
GetMem(buffer, n);
ReadFile(hFile, buffer^, n, r, nil);
p := buffer;
Move(p^, RegStrucsToRead
, HEAD_SIZE);
Inc(p, HEAD_SIZE);
RegStrucsToRead.Name := p;
Inc(p, StrLen(p) + 1);
RegStrucsToRead.Value := p;
FreeMem(buffer);
end;
CloseHandle(hFile);
end;
//Overwrite 变量如果为 True 表示重写记录文件,否则是追加模式
//RegStrucsToWrite 需要人工初始化,并且事先赋值
procedure WriteRegFile(const FileName: string
RegStrucsToWrite: TRegStrucs;
const Overwrite: Boolean = False);
var
hFile: THandle;
n, w, i: DWORD;
buffer, p: PChar;
begin
n := 0;
if not Overwrite then
begin
hFile := CreateFile(PChar(FileName), GENERIC_READ or GENERIC_WRITE, 0, nil, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
if GetFileSize(hFile, nil) > 0 then
ReadFile(hFile, n, SizeOf, w, nil);
SetFilePointer(hFile, 0, nil, FILE_BEGIN);
end
else hFile := CreateFile(PChar(FileName), GENERIC_WRITE, 0, nil, CREATE_ALWAYS, 0, 0);
Inc(n, Length(RegStrucsToWrite));
WriteFile(hFile, n, SizeOf, w, nil);
SetFilePointer(hFile, 0, nil, FILE_END);
for i := 0 to Length(RegStrucsToWrite) - 1 do
begin
n := SizeOf + HEAD_SIZE + Length(RegStrucsToWrite.Name) + Length(RegStrucsToWrite.Value) + 2;
GetMem(buffer, n);
p := buffer;
Move(n, p^, SizeOf);
Inc(p, SizeOf);
Move(RegStrucsToWrite, p^, HEAD_SIZE);
Inc(p, HEAD_SIZE);
Move(PChar(RegStrucsToWrite.Name)^, p^, Length(RegStrucsToWrite.Name));
Inc(p, Length(RegStrucsToWrite.Name));
p^ := #0;
Inc(p);
Move(PChar(RegStrucsToWrite.Value)^, p^, Length(RegStrucsToWrite.Value));
Inc(p, Length(RegStrucsToWrite.Value));
p^ := #0;
WriteFile(hFile, buffer^, n, w, nil);
FreeMem(buffer);
end;
CloseHandle(hFile);
end;
6、也可以用 Delphi 自带的 AssignFile、CloseFile、Reset、Rewrite、Write、Read 之类的函数或过程,但是 Delphi 的 TextFile 文件类型会把 Write(f, 2) 中的整数 2 直接当作字符写入文件;而对于无类型文件,Write(f, 'abc') 之类的函数根本就不能用。