Почему 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;
Другие вопросы по тегам