Как заставить Delphi 2006 TStringList.LoadFromFile загружать файлы UTF-16

У меня есть приложение Delphi 2006, в которое я добавляю код для обработки некоторых сгенерированных файлов данных CSV. TStringList.LoadFromFile давал странные результаты, и я только что выяснил, что файлы закодированы в UTF-16.

Обновление до XE планируется, но пока не вариант.

Каков самый простой способ обработки этих файлов с помощью D2006? Я предполагаю, что их можно без проблем сопоставить с 8-битным ASCII — это «чистый» CSV — просто цифры, запятые и т. д., и я не думаю, что будут какие-то проблемы с символами, которых нет в 8 - битовый набор.


person rossmcm    schedule 28.06.2011    source источник


Ответы (2)


TStringList не поддерживает UTF-16 в D2006, поэтому вам придется загружать и декодировать данные файла вручную, прежде чем помещать вывод в файл 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;
person Remy Lebeau    schedule 01.07.2011
comment
Спасибо @Remy. Ваш пример работает, но файл включает заголовок спецификации $FF $FE (поэтому я получаю '?', добавленный в качестве первого символа первой строки), и я не уверен в правильном способе ссылки из второго символа до конца потока.? - person rossmcm; 02.07.2011
comment
Вам нужно будет присвоить указатель TMemoryStream.Memory локальной переменной, а затем продвигать его по мере необходимости. Я отредактировал пример, чтобы показать это. - person Remy Lebeau; 04.07.2011

На всякий случай существует риск потери данных, вы можете попробовать использовать JCL TJclWideStringList.

person Warren P    schedule 14.07.2011