简体   繁体   中英

Why TFileStream.write produces incorrect data? Dephi 7

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;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM