如何防止TStrings.SaveToStream编写BOM?

问题描述 投票:0回答:2

我正在使用Delphi XE3。

在我的代码中,我需要创建一个文件流,然后将自己的数据以及几个TStringList的内容写入其中。该文件为UTF-16LE格式。

因此,我的代码:

FileStream := TFileStream.Create('D:\MyFile.dat', fmCreate or fmOpenWrite or fmShareExclusive);

try
  // Write some data to FileStream

  // Write contents of StringList1 into FileStream
  StringList1.SaveToStream(FileStream, TEncoding.Unicode);

  // Write some more data to FileStream

  // Write contents of StringList2 into FileSteram
  StringList2.SaveToStream(FileStream, TEncoding.Unicode);
finally
  FileStream.Free;
end;

执行代码后,每次调用StringList1.SaveToStream(FileStream,TEncoding.Unicode)时,我都会发现问题。它将先写BOM(0xFFFE),然后在字符串列表中跟实际字符串。

因此,我得到这样的Unicode文件:

0xFFFE(第一个由我自己编写)

((某些数据)]

0xFFFE(StringList1的内容)

((某些数据)]

0xFFFE(StringList2的内容)

但是我不希望这是因为文件的开头应该只有一个0xFFFE。因此,我只是想知道如何防止StringList1.SaveToStream在写入实际的字符串列表之前写入0xFFFE BOM表?

delphi delphi-xe3 tstringlist
2个回答
1
投票

您可以先使用SaveToStream()保存到TMemoryStream,然后设置该流的Position跳过其中的BOM,并将其其余数据保存到TFileStream

procedure WriteUnicodeStrings(AStream: TStream; AStrings: TStrings);
var
  MS: TMemoryStream;
begin
  MS := TMemoryStream.Create;
  try
    AStrings.SaveToStream(MS, TEncoding.Unicode);
    if MS.Size > 2 then
    begin
      MS.Position := 2;
      AStream.CopyFrom(MS, MS.Size-2);
    end;
  finally
    MS.Free;
  end;
end;
...
FileStream := TFileStream.Create('D:\MyFile.dat', fmCreate or fmOpenWrite or fmShareExclusive);
try
  // Write some data to FileStream
  WriteUnicodeStrings(FileStream, StringList1);
  // Write some more data to FileStream
  WriteUnicodeStrings(FileStream, StringList2);
finally
  FileStream.Free;
end;

或者,您可以简单地从SysUtils.TUnicodeEncoding派生一个类并重写其GetPreamble()方法以不返回任何BOM,然后使用该类而不是使用TEncoding.Unicode

type
  TMyUnicodeEncoding = class(TUnicodeEncoding)
  public
    function GetPreamble: TBytes; override;
  end;

function TMyUnicodeEncoding.GetPreamble: TBytes;
begin
  Result := nil;
end;

procedure WriteUnicodeStrings(AStream: TStream; AStrings: TStrings);
var
  Enc: TMyUnicodeEncoding;
begin
  Enc := TMyUnicodeEncoding.Create;
  try
    AStrings.SaveToStream(AStream, Enc);
  finally
    Enc.Free;
  end;
end;
...
FileStream := TFileStream.Create('D:\MyFile.dat', fmCreate or fmOpenWrite or fmShareExclusive);
try
  // Write some data to FileStream
  WriteUnicodeStrings(FileStream, StringList1);
  // Write some more data to FileStream
  WriteUnicodeStrings(FileStream, StringList2);
finally
  FileStream.Free;
end;

0
投票

我为我的问题找到了另一个解决方案。

TStrings具有WriteBOM属性,该属性将控制使用SaveToStream或SaveToFile时是写出BOM表。

因此,使用以下代码将禁用BOM:

  StringList1.WriteBOM := False;
  StringList1.SaveToStream(FileStream, TEncoding.Unicode);
© www.soinside.com 2019 - 2024. All rights reserved.