У меня есть эта функция в Delphi 2009/2010.

Он возвращает мусор, теперь, если я изменю типы char, pchar на Ansichar, Pansichar, он вернет текст, но весь иностранный текст Unicode - мусор. это сводит меня с ума. Я пробовал всякие штуки уже 2 дня. Я думал, что понял эту ерунду с юникодом, но, думаю, я не помог. Пожалуйста, спасибо, Филипп Ватель

function GetInetFileAsString(const fileURL: string): string;
const
  C_BufferSize = 1024;
var
  sAppName: string;
  hSession,
    hURL: HInternet;

  Buffer: array[0..C_BufferSize] of Char;
  BufferLen: DWORD;

  strPageContent: string;
  strTemp: string;

begin
  Result := '';
  sAppName := ExtractFileName(Application.ExeName);
  hSession := InternetOpen(PChar(sAppName), INTERNET_OPEN_TYPE_PRECONFIG, nil,
    nil, 0);
  try
    hURL := InternetOpenURL(hSession, PChar(fileURL), nil, 0, 0, 0);
    try
      strPageContent := '';
      repeat
        InternetReadFile(hURL, @Buffer, SizeOf(Buffer), BufferLen);
        SetString(strTemp, PChar(@buffer), BufferLen div SizeOf(Char));
        strPageContent := strPageContent + strTemp;
      until BufferLen = 0;
      Result := strPageContent;
    finally
      InternetCloseHandle(hURL)
    end
  finally
    InternetCloseHandle(hSession)
  end
end;
2
Philippe Watel 4 Дек 2009 в 17:20

2 ответа

Начиная с Delphi 2009, String является псевдонимом для UnicodeString, который содержит данные UTF-16. С другой стороны, HTML-страница обычно кодируется с использованием многобайтовой кодировки Ansi (в настоящее время обычно используется UTF-8, но не всегда). Ваш текущий код будет работать только в том случае, если HTML закодирован как UTF-16, что бывает очень редко. Вы не должны считывать необработанные байты HTML в UnicodeString напрямую. Вам необходимо сначала загрузить все данные в TBytes, RawByteString, TMemoryStream или другой подходящий контейнер байтов по вашему выбору, а затем выполнить преобразование Ansi-> Unicode на основе кодировка, указанная в заголовке ответа HTTP Content-Type. Вы можете использовать заголовок запроса Accept-charset, чтобы сообщить серверу, какую кодировку вы предпочитаете для отправки данных, и если сервер не может использовать эту кодировку, он должен отправить ответ 406 Not Acceptable (хотя это МОЖЕТ по-прежнему отправлять успешный ответ с неприемлемой кодировкой, если он решит игнорировать заголовок вашего запроса, поэтому вы должны учитывать это).

Попробуйте что-то вроде этого:

function GetInetFileAsString(const fileURL: string): string;
const
  C_BufferSize = 1024;
var
  sAppName: string;
  hSession, hURL: HInternet;
  Buffer: array of Byte;
  BufferLen: DWORD;
  strHeader: String;
  strPageContent: TStringStream;
begin
  Result := '';
  SetLength(Buffer, C_BufferSize);
  sAppName := ExtractFileName(Application.ExeName);
  hSession := InternetOpen(PChar(sAppName), INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0);
  try
    strHeader := 'Accept-Charset: utf-8'#13#10;
    hURL := InternetOpenURL(hSession, PChar(fileURL), PChar(strHeader), Length(strHeader), 0, 0);
    try
      strPageContent := TStringStream.Create('', TEncoding.UTF8);
      try
        repeat
          if not InternetReadFile(hURL, PByte(Buffer), Length(Buffer), BufferLen) then
            Exit;
          if BufferLen = 0 then
            Break;
          strPageContent.WriteBuffer(PByte(Buffer)^, BufferLen);
        until False;
        Result := strPageContent.DataString;
        // or, use HttpQueryInfo(HTTP_QUERY_CONTENT_TYPE) to get
        // the Content-Type header, parse out its "charset" attribute,
        // and convert strPageContent.Memory to UTF-16 accordingly...
      finally
        strPageContent.Free;
      end;
    finally
      InternetCloseHandle(hURL);
    end
  finally
    InternetCloseHandle(hSession);
  end;
end;
4
Remy Lebeau 27 Окт 2015 в 05:10
Я успешно использовал этот код, но я изменил буфер на объявленный буфер динамического массива: TArray; а затем SetLength(buffer, C_BufferSize). Кроме того, перед циклом я добавил целочисленный параметр var, равный нулю, и увеличивал его с помощью bufferLen после каждого вызова InternetReadFile. Позволяет мне узнать размер загруженного файла.
 – 
MarkAurelius
27 Окт 2015 в 04:56

Моя первая мысль — добавить в запрос правильный заголовок AcceptEncoding/CharSet:

Например:

Accept-Charset: ISO-8859-1, utf-8; q = 0,7, *; q = 0,7

0
Lloyd 4 Дек 2009 в 17:22