如何防止TStrings.SaveToStream写BOM?
How to Prevent TStrings.SaveToStream from writing the BOM?
我正在使用 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?
您可以先使用 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
派生一个 class 并覆盖它的 GetPreamble()
方法以不 return 任何 BOM,然后使用那个 class而不是使用 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;
我为我的问题找到了另一个解决方案。
TStrings 有一个 WriteBOM 属性,它将控制在使用 SaveToStream 或 SaveToFile 时是否写出 BOM。
因此,使用以下代码将禁用 BOM:
StringList1.WriteBOM := False;
StringList1.SaveToStream(FileStream, TEncoding.Unicode);
我正在使用 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?
您可以先使用 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
派生一个 class 并覆盖它的 GetPreamble()
方法以不 return 任何 BOM,然后使用那个 class而不是使用 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;
我为我的问题找到了另一个解决方案。
TStrings 有一个 WriteBOM 属性,它将控制在使用 SaveToStream 或 SaveToFile 时是否写出 BOM。
因此,使用以下代码将禁用 BOM:
StringList1.WriteBOM := False;
StringList1.SaveToStream(FileStream, TEncoding.Unicode);