Почему TFileStream.write выдает неверные данные? Дефи 7
Я пытался создать функцию / метод, который должен писать в файл с заголовком, заполненным нулями
header := StringOfChar(char(0), 11*offsetSize);
Но когда я проверяю файл, который был создан, он имеет следующие значения (шестнадцатеричные):
C026A200160000000100000006000000264C656B63650000B2000000B04D45005C1EA200306CA20000000000
Я ожидал, что выходной файл должен содержать
0000 0000 0000 0000 0000 0000
Тогда я также попытался заполнить его chr(1)
и результат был похож:
C026A200160000000100000006000000264C656B63650000B2000000B04D45005C1EA200306CA20000000000
(Выглядит так же).
Когда я отлаживаю в Delphi 7, я смотрю заголовок, когда он заполнен нулями:
#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
Когда я заполняю его chr(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#1
Итак, мой вопрос: почему это происходит? Что я делаю не так, что выходной файл содержит неверные данные?
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.
1 ответ
Причина, по которой ваши данные неправильно записываются в файл, заключается в том, что вы не передаете header
в Write()
правильно. Write()
принимает нетипизированный var
в качестве ввода, и вы передаете его header
переменная как есть, так что вы передаете Write()
адрес памяти header
сам. Но string
содержит указатель на символьные данные, которые хранятся в другом месте в памяти. Итак, чтобы записать эти данные в ваш файл, вам нужно разыменовать string
указатель, так что вы вместо этого передаете в память адрес символьных данных.
Кроме того, если вы не хотите проверять возвращаемое значение Write()
для ошибок, вы должны использовать WriteBuffer()
вместо.
Попробуй это:
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;
Или же:
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;
Тем не менее, вы действительно не должны использовать string
для двоичных данных (особенно, если вы когда-нибудь планируете обновить свой проект до Delphi 2009+. Вы должны использовать record
или массив байтов вместо этого, например:
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;
Или же:
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;
Или же:
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;