【问题标题】:Downloading UTF-8 file with libcurl (ANSI works fine)使用 libcurl 下载 UTF-8 文件(ANSI 工作正常)
【发布时间】:2015-10-20 20:22:13
【问题描述】:

我正在借助libcurl 编写一个简单的文件下载器。下面是从 HTTP 服务器下载文件的代码:

static size_t WriteCallback(void *contents, size_t size, size_t nmemb, void *userp) {
    ((std::string*)userp)->append((char*)contents, size * nmemb);
    return size * nmemb;
}

std::wstring result; //result with polish letters (ą, ę etc.)
CURL *curl;
CURLcode res;
std::string readBuffer;

curl = curl_easy_init();
ERROR_HANDLE(curl, L"CURL could not been inited.", MOD_INTERNET);
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
curl_easy_setopt(curl, CURLOPT_USERPWD, (login + ":" + password).c_str()); //e.g.: "login:password"
curl_easy_setopt(curl, CURLOPT_POST, true);
//curl_easy_setopt(curl, CURLOPT_ENCODING, "UTF-8"); //does not change anything
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);

result = C::toWString(readBuffer);
return res == 0; //0 = OK

当我要下载的文件被编码为ANSI(根据例如记事本++)时,它工作正常。但是当我尝试下载UTF-8 文件(UTF-8 without BOM)时,由于编码问题,我收到了一些字符(例如波兰字母)的错误。

例如,我为两个具有相同文本(“to jest teść to”)的文件运行代码并将其保存到std::wstringresult 来自ANSI 文件和result2(有问题)来自UTF-8 版本:

这两个文件都在服务器上打开,例如Notepad++ 显示正确的文本。

那么,我怎样才能用libcurl 获取UTF-8 文件 内容并使用正确的编码将其保存到std::wstring(所以Visual 的调试器Studio 会显示为to jest teść to)?

【问题讨论】:

  • 将 UTF-8 存储在宽字符串中并没有多大意义。这样做有什么意义?
  • 代码未将 UTF-8 存储在 std::wstring 中。它将 UTF-8 存储在 std::string 中,然后在下载完成后将其转换为 std::wstring。问题在于转换,而不是下载本身。
  • @MrEricSir 我认为(如果我错了,请纠正我) wstring 可以存储宽字符,并且可以很好地与 UTF-8 配合使用(它将使用超过 1 个字节来存储我的波兰语文本的字符)。调试器也显示了这一点。并且将其存储在字符串中还不清楚(find 等方法也无法正常工作)。
  • @PolGraphic 不,顾名思义,UTF-8 旨在以 8 位字符存储。 UTF-16 期望以 16 位字符存储。在 Windows 上 wchar_t 是一个 16 位字符,因此您可以将 UTF-16 字符串存储在 wstring 中。
  • @MrEricSir 我不是该领域的专家,但我知道我在std::string 的 UTF-8/波兰语字符方面遇到了很多问题(查找方法,@987654342 @ 和一些希望 wchar_t 仅举几例的 Windows 函数)并在阅读了 string vs wstring 的几个问题后(例如 stackoverflow.com/questions/402283/stdwstring-vs-stdstring 说“对于 Windows 几乎总是使用 wstring)我切换到 @ 987654345@,我对此很满意。

标签: c++ curl encoding utf-8 libcurl


【解决方案1】:

这不是 libcurl 问题。您将原始数据存储在 std::string 中,然后在下载完成后将其转换为 std::wstring。您必须查看 HTTP 响应中报告的字符集,并将数据相应地解码为 std::wstringC::toWString() 没有字符集的概念,所以你应该使用其他东西,比如 ICONV 或 ICU。或者,如果您知道数据始终是 UTF-8,请手动进行转换(UTF 转换很容易手动编码),或者使用 C++11 的内置 UTF 转换(使用 std::wstring_convert 类)。

【讨论】:

  • 如何查看带有 libcurl 请求的 HTTP 响应中报告的字符集?
  • 该字符集位于Content-Type 响应标头中,您可以使用curl_easy_getinfo() 将其info 参数设置为CURLINFO_CONTENT_TYPE 来检索它。
  • 谢谢。对于我得到的一些文件,例如text/html; charset=ISO-8859-1,但对于其中许多人来说,我只有text/plain(在ANSIUTF-8 情况下)。我能做点什么吗?
  • libcurl 报告服务器提供的内容。如果未指定字符集,则必须解析内容(在 HTML 或 XML 的情况下),否则使用报告媒体类型的默认字符集。对于通过 HTTP 传递的text/plain,即ISO-8859-1,根据 RFC 2616 第 3.7.1 节:“当发送方未提供显式字符集参数时,“文本”类型的媒体子类型被定义为具有通过 HTTP 接收时的默认字符集值为“ISO-8859-1”。非“ISO-8859-1”或其子集字符集中的数据必须使用适当的字符集值进行标记。
  • 如果您收到的 UTF-8 文本文件在 Content-Type 标头中没有 charset=utf-8 声明,则服务器不符合 HTTP 规范。
【解决方案2】:

libcurl 不会为您转换或翻译内容。它会将服务器发出的确切字节传送到您的应用程序。

您可以使用 HTTP Accept 标头等来影响服务器响应的内容,但是如果您对收到的内容不满意,则需要检查收到的字符集并自行进行相应的转换。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-04-09
    • 2018-10-24
    • 1970-01-01
    • 2011-11-20
    • 1970-01-01
    • 1970-01-01
    • 2011-09-22
    • 2013-09-11
    相关资源
    最近更新 更多