I tried to create a function/method which should write to a file with a header filled with zeros
header := StringOfChar(char(0), 11*offsetSize);
But when I check the file which was created, it has the following values (hex):
C026A200160000000100000006000000264C656B63650000B2000000B04D45005C1EA200306CA20000000000
I expected the output file should contain
0000 0000 0000 0000 0000 0000
Then I also tried to fill it with chr(1)
and the result was similar:
C026A200160000000100000006000000264C656B63650000B2000000B04D45005C1EA200306CA20000000000
(It looks the same).
When I debug in Delphi 7, I watch the header when it is filled with zeros:
#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0
When I fill it with chr(1)
then it contains...
#1#1#1#1#1#1#1#1#1#1#1#1#1#1#1#1#1#1#1#1#1#1#1#1#1#1#1#1#1#1#1#1#1#1#1#1#1#1#1#1#1#1#1#1
So my question is, why is this happening? What am I doing wrong that the output file contains the wrong data?
unit Dictionary_io;
interface
uses
Classes, Windows, SysUtils, Dialogs;
const
offsetTableEntriesCount = 10;
type
TCountType = dword;
TOffsetType = dword;
TTextType = ANSIString;
const
testItemsCount = 1;
type
Dictionary = class
private
fsInput, fsOutput: TFileStream;
fileName: string;
msOffsets: TMemoryStream;
offsetSize: TOffsetType;
ofsTableEntries: TCountType;
lng: integer;
itemsCount: byte;
header: TTextType;
public
constructor Create;
procedure dicRewrite;
end;
implementation
constructor Dictionary.Create;
begin
offsetSize := sizeof(offsetSize);
end;
procedure Dictionary.dicRewrite;
var
i: integer;
begin
itemsCount := 0;
header := StringOfChar(char(0), 11*offsetSize);
try
fileName := 'A:\test.bin';
if FileExists(fileName) then
DeleteFile(fileName);
fsOutput := TFileStream.Create(fileName, fmCreate);
try
fsOutput.Write(header,Length(header));
finally
end;
finally
fsOutput.Free;
end;
end;
end.
The reason your data is not being written to the file correctly is because you are not passing the header
to Write()
correctly. Write()
takes an untyped var
as input, and you are passing it the header
variable as-is, so you are passing Write()
the memory address of header
itself. But a string
contains a pointer to character data that is stored elsewhere in memory. So, in order to write that data to your file, you need to dereference the string
pointer so you pass in the memory address of the character data instead.
Also, if you do not want to check the return value of Write()
for errors, you should use WriteBuffer()
instead.
Try this:
procedure Dictionary.dicRewrite;
var
i: integer;
begin
itemsCount := 0;
header := StringOfChar(#0, 11*offsetSize);
fileName := 'A:\test.bin';
fsOutput := TFileStream.Create(fileName, fmCreate);
try
fsOutput.WriteBuffer(header[1], Length(header));
finally
fsOutput.Free;
end;
end;
Or:
procedure Dictionary.dicRewrite;
var
i: integer;
begin
itemsCount := 0;
header := StringOfChar(#0, 11*offsetSize);
fileName := 'A:\test.bin';
fsOutput := TFileStream.Create(fileName, fmCreate);
try
fsOutput.WriteBuffer(PAnsiChar(header)^, Length(header));
finally
fsOutput.Free;
end;
end;
That being said, you really should not be using a string
for binary data (especially if you ever plan on upgrading your project to Delphi 2009+. You should use a record
or an array of bytes instead, eg:
private
header: array of Byte;
procedure Dictionary.dicRewrite;
var
i: integer;
begin
itemsCount := 0;
SetLength(header, 11*offsetSize);
FillChar(header[0], Length(header), #0);
fileName := 'A:\test.bin';
fsOutput := TFileStream.Create(fileName, fmCreate);
try
fsOutput.WriteBuffer(header[0], Length(header));
finally
fsOutput.Free;
end;
end;
Or:
procedure Dictionary.dicRewrite;
var
i: integer;
begin
itemsCount := 0;
SetLength(header, 11*offsetSize);
FillChar(PByte(header)^, Length(header), #0);
fileName := 'A:\test.bin';
fsOutput := TFileStream.Create(fileName, fmCreate);
try
fsOutput.WriteBuffer(PByte(header)^, Length(header));
finally
fsOutput.Free;
end;
end;
Or:
private
header: array[0..(11*offsetSize)-1] of Byte;
procedure Dictionary.dicRewrite;
var
i: integer;
begin
itemsCount := 0;
FillChar(header, Length(header), #0);
fileName := 'A:\test.bin';
fsOutput := TFileStream.Create(fileName, fmCreate);
try
fsOutput.WriteBuffer(header, SizeOf(header));
finally
fsOutput.Free;
end;
end;