在 Scott Meyers 的“Effective STL”一书中,有一个很好的例子,将整个文本文件读入 std::string 对象:
std::string sData;
/*** Open the file for reading, binary mode ***/
std::ifstream ifFile (“MyFile.txt”, std::ios_base::binary); // Open for input, binary mode
/*** Read in all the data from the file into one string object ***/
sData.assign (std::istreambuf_iterator <char> (ifFile),
std::istreambuf_iterator <char> ());
请注意,它将其读取为 8 字节字符。这很好用。最近虽然我需要读取一个包含 Unicode 文本的文件(即每个字符两个字节)。但是,当我尝试(天真地)更改它以将数据从 Unicode 文本文件读取到 std::wstring 对象时,如下所示:
std::wstring wsData;
/*** Open the file for reading, binary mode ***/
std::wifstream ifFile (“MyFile.txt”, std::ios_base::binary); // Open for input, binary mode
/*** Read in all the data from the file into one string object ***/
wsData.assign (std::istreambuf_iterator <wchar_t> (ifFile),
std::istreambuf_iterator <wchar_t> ());
我得到的字符串虽然是宽字符,但仍然具有备用空值。例如,如果文件包含 Unicode 字符串“ABC”,则文件的字节(忽略 0xFF、0xFE 的 Unicode 前导字节)为:<'A'> <0> <'B'> <0> <' C'> <0>
上面的第一个代码片段将正确生成 (char) 字符串的以下内容:
sData [0] = 'A'<br> sData [1] = 0x00
sData [2] = 'B'<br> sData [3 ] = 0x00
sData [4] = 'C'<br> sData [5] = 0x00
但是,当运行第二个代码片段时,它会意外地导致 (wchar_t) 字符串的以下内容:
wsData [0] = L'A'<br> wsData [1] = 0x0000
wsData [2] = L'B '<br> wsData [3] = 0x0000
wsData [4] = L'C'<br> wsData [5] = 0x0000
就好像文件仍在被逐字节读取,然后只是简单地翻译成单独的 wchar_t 字符。
我会认为专门用于 wchar_t 的 std::istreambuf_iterator 应该导致文件一次读取两个字节,不是吗?如果不是,那它的目的是什么?
我已经追踪到模板(不容易的壮举;-),并且迭代器确实似乎仍然在逐字节读取文件并将其传递给其内部转换例程,该例程尽职尽责地声明转换是在每个字节之后完成的(不是仅在收到 2 个字节后)。
我已经在网络上搜索了许多网站(包括这个网站)来寻找这个看似微不足道的任务,但没有找到对这种行为的解释或一个很好的替代方案,它不涉及比我认为必要的更多代码(例如,A Google网络搜索也会产生相同的第二个代码片段作为可行的代码段)。
我发现唯一可行的是以下内容,我认为这是作弊,因为它需要直接访问 wstring 的内部缓冲区,然后对其进行类型强制。
std::wstring wsData;
/*** Open the file for reading, binary mode ***/
std::wifstream ifFile (“MyFile.txt”, std::ios_base::binary); // Open for input, binary mode
wsData.resize (<Size of file in bytes> / sizeof (wchar_t));
ifFile.read ((char *) &wsData [0], <Size of file in bytes>);
哦,为了避免不可避免的“为什么以二进制模式打开文件,为什么不以文本模式打开文件”的问题,打开是故意的,好像文件是以文本模式打开的(默认),这意味着 CR/LF ("\ r\n" 或 0x0D0A) 序列将仅转换为 LF("\n" 或 0x0A)序列,而文件的纯字节读取将保留它们。无论如何,对于那些顽固分子来说,改变这一点毫无疑问是没有效果的。
所以这里有两个问题,为什么第二种情况不能像预期的那样工作(即,这些迭代器发生了什么),以及你最喜欢的将 Unicode 字符文件加载到 wstring 中的“犹太 STL 方式”是什么?
我在这里想念什么;它一定很愚蠢。
克里斯