如何使用Delphi 2006的TStringList.LoadFromFile方法加载UTF-16文件

3

我有一个Delphi 2006的应用程序,需要添加代码来处理生成的CSV数据文件。TStringList.LoadFromFile返回了奇怪的结果,后来我发现这些文件以UTF-16编码。

计划升级到XE,但目前不是一个选项。

如何在D2006中处理这些文件是最简单的途径? 我假设它们可以映射到8位ASCII而没有任何问题 - 它们是“纯粹”的CSV - 只有数字和逗号等字符,我认为不会出现任何与8位字符集不兼容的字符。

2个回答

4

TStringList在D2006版本中不支持UTF-16编码,因此您需要手动加载和解码文件数据,然后将输出放入您的TStringList中。例如:

var
  sl: TStringList;
  {$IFNDEF D2009_OR_LATER}
  ms: TMemoryStream;
  ptr: PWideChar;
  s: AnsiString;
  dlen, slen: Integer;
  {$ENDIF}
begin
  ...
  {$IFDEF D2009_OR_LATER}
  sl.LoadFromFile('...', TEncoding.Unicode);
  {$ELSE}
  ms := TMemoryStream.Create;
  try
    ms.LoadFromFile('...');
    ptr := PWideChar(ms.Memory);
    dlen := ms.Size div SizeOf(WideChar);
    if (dlen >= 1) and (PWord(ptr)^ = $FEFF) then
    begin
      Inc(ptr);
      Dec(dlen);
    end;
    slen := WideCharToMultiByte(0, 0, ptr, dlen, nil, 0, nil, nil);
    if slen > 0 then begin
      SetLength(s, slen);
      WideCharToMultiByte(0, 0, ptr, dlen, PAnsiChar(s), slen, nil, nil));
    end;
    sl.Text := s;
  finally
    ms.Free;
  end;
  {$ENDIF}
  ...
end;

谢谢@Remy。你的例子很好用,但是文件包含BOM头$FF $FE(所以我最终得到了一个'?'作为第一个字符串的第一个字符),而且我不确定正确的方式是从第二个字符引用到流的末尾。 - rossmcm
1
你需要将TMemoryStream.Memory指针分配给一个本地变量,然后根据需要进行调整。我已经编辑了示例以展示这一点。 - Remy Lebeau

1

如果有数据丢失的风险,您可以尝试使用JCL TJclWideStringList。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接