如何在Windows平台上将Unicode (UTF-8) 文件读入到 wstring
中?
在支持C++11的情况下,您可以使用std::codecvt_utf8 facet,该特性封装了UTF-8编码的字节串和UCS2或UCS4字符串之间的转换,并可用于读写UTF-8文件,包括文本和二进制文件。
要使用facet,通常需要创建locale object 将特定的本地环境定义为一组特性的文化特定信息的封装体。一旦您有了locales对象,就可以通过将其与流缓冲区相结合来imbue它:
#include <sstream>
#include <fstream>
#include <codecvt>
std::wstring readFile(const char* filename)
{
std::wifstream wif(filename);
wif.imbue(std::locale(std::locale::empty(), new std::codecvt_utf8<wchar_t>));
std::wstringstream wss;
wss << wif.rdbuf();
return wss.str();
}
可以像这样使用:std::wstring wstr = readFile("a.txt");
或者你可以在使用字符串流之前设置全局C++本地化环境,这将导致所有未来对std::locale
默认构造函数的调用返回全局C++本地化环境的副本(然后你不需要显式地把它注入到流缓冲区中):
std::locale::global(std::locale(std::locale::empty(), new std::codecvt_utf8<wchar_t>));
new codecvt_utf8
需要相应的 delete
吗? - Dmitri Nesteruk根据@Hans Passant的评论,最简单的方法是使用_wfopen_s。使用模式rt, ccs=UTF-8
打开文件。
这里还有另一种完全使用 C++ 的解决方案,至少可在 VC++ 2010 中使用:
#include <locale>
#include <codecvt>
#include <string>
#include <fstream>
#include <cstdlib>
int main() {
const std::locale empty_locale = std::locale::empty();
typedef std::codecvt_utf8<wchar_t> converter_type;
const converter_type* converter = new converter_type;
const std::locale utf8_locale = std::locale(empty_locale, converter);
std::wifstream stream(L"test.txt");
stream.imbue(utf8_locale);
std::wstring line;
std::getline(stream, line);
std::system("pause");
}
除了locale::empty()
(这里locale::global()
也可能适用)和basic_ifstream
构造函数的wchar_t*
重载之外,这应该是相当符合标准的(当然,“标准”指的是C++0x)。
这里是一个仅适用于Windows平台的特定功能:
size_t GetSizeOfFile(const std::wstring& path)
{
struct _stat fileinfo;
_wstat(path.c_str(), &fileinfo);
return fileinfo.st_size;
}
std::wstring LoadUtf8FileToString(const std::wstring& filename)
{
std::wstring buffer; // stores file contents
FILE* f = _wfopen(filename.c_str(), L"rtS, ccs=UTF-8");
// Failed to open file
if (f == NULL)
{
// ...handle some error...
return buffer;
}
size_t filesize = GetSizeOfFile(filename);
// Read entire file contents in to memory
if (filesize > 0)
{
buffer.resize(filesize);
size_t wchars_read = fread(&(buffer.front()), sizeof(wchar_t), filesize, f);
buffer.resize(wchars_read);
buffer.shrink_to_fit();
}
fclose(f);
return buffer;
}
使用方式如下:
std::wstring mytext = LoadUtf8FileToString(L"C:\\MyUtf8File.txt");
请注意整个文件将被加载到内存中,因此您可能不希望将其用于非常大的文件。
t
以及ccs=UTF-8
会导致字符在读取和写入流时被转换。 - AshleysBrainccs=
模式说明符的情况下使用_wfopen
。您需要同时使用_wfopen
(根据手册,应优先使用_wfopen_s
)和ccs=UTF-8
。 - Philipp#include <iostream>
#include <fstream>
#include <string>
#include <locale>
#include <cstdlib>
int main()
{
std::wifstream wif("filename.txt");
wif.imbue(std::locale("zh_CN.UTF-8"));
std::wcout.imbue(std::locale("zh_CN.UTF-8"));
std::wcout << wif.rdbuf();
}
最近处理了所有编码问题,解决方法如下。最好使用std::u32string
,因为它在所有平台上具有稳定的大小,并且大多数字体都支持utf-32格式。(文件仍应该是utf-8格式)
std::u32string readFile(std::string filename) {
std::basic_ifstream<char32_t> fin(filename);
std::u32string str{};
std::getline(fin, str, U'\0');
return str;
}
可以随意使用标准函数,除了 gcount
,并且只将 tellg
的结果保存到 pos_type
中。此外,请确保将分隔符传递给 std::getline
(如果不这样做,该函数会抛出异常 std::bad_cast
)。
wstring
只是一个由16位整数组成的数组。您可以在其中存储UCS-2或UTF-16数据或任何您喜欢的内容。现在,大多数Windows API都接受UTF-16字符串。 - Philippiostreams
库除了允许使用Unicode文件名外,并没有提供任何Unicode支持。在C++中使用Unicode的所有解决方案都是纯C解决方案,要么直接使用Windows API,要么使用C库的非标准扩展。 - Philipp这可能有点简单粗暴,不过如何将文件读取为普通字节,然后将字节缓冲区转换为wchar_t*?
类似于:
#include <iostream>
#include <fstream>
std::wstring ReadFileIntoWstring(const std::wstring& filepath)
{
std::wstring wstr;
std::ifstream file (filepath.c_str(), std::ios::in|std::ios::binary|std::ios::ate);
size_t size = (size_t)file.tellg();
file.seekg (0, std::ios::beg);
char* buffer = new char [size];
file.read (buffer, size);
wstr = (wchar_t*)buffer;
file.close();
delete[] buffer;
return wstr;
}