В книге "Эффективный 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 (т.е. Два байта за char). Однако, когда я пытаюсь (наивно) изменить его, чтобы читать данные из текстового файла 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> ());
Строка, которую я возвращаю, имея широкие символы, по-прежнему имеет альтернативные нули. Например, если в файле содержится строка Юникода "ABC", байты файла (игнорирование младших байтов Юникода 0xFF, 0xFE): <A> < 0 <B> < 0 <C> < 0 >
Первый вышеописанный фрагмент кода корректно приведет к следующему содержимому строки (char):
sData [0] = 'A
sData [1] = 0x00
sData [2] = 'B
sData [3] = 0x00
sData [4] = 'C
sData [5] = 0x00
Однако, когда выполняется второй фрагмент кода, он нежелательно приводит к следующему содержимому строки (wchar_t):
wsData [0] = L'A
wsData [1] = 0x0000
wsData [2] = L'B
wsData [3] = 0x0000
wsData [4] = L'C
wsData [5] = 0x0000
Как будто файл все еще читается байтом байтом, а затем просто переводится на отдельные символы wchar_t.
Я бы подумал, что std:: istreambuf_iterator, специализирующийся на wchar_t, должен был заставить файл читать два байта за раз, не так ли? Если нет, то какова его цель?
Я проследил в шаблоны (нет легкого feat;-), и итератор действительно все еще, кажется, читает байтовый файл байтом и передает его в свою внутреннюю процедуру преобразования, которая покорно заявляет, что преобразование выполняется после каждого байт (не только после получения 2 байтов).
Я искал несколько сайтов в Интернете (включая этот) для этой кажущейся тривиальной задачи, но не нашел объяснения этого поведения или хорошей альтернативы, которая не включает в себя больше кода, чем я считаю необходимым (например, Поиск Google в Интернете производит тот же самый второй фрагмент кода, что и жизнеспособная часть кода).
Единственное, что я обнаружил, что работает, - это следующее, и я считаю, что это чит, поскольку ему нужен прямой доступ к внутреннему буферу wstrings, а затем type-coerces его при этом.
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), тогда как чистое байтовое чтение файла сохранит их. Несмотря на это, для тех, кто несгибался, изменение, которое, неудивительно, не имело никакого эффекта.
Итак, есть два вопроса: почему второй случай не работает, как можно было бы ожидать (т.е. что происходит с этими итераторами), и каков будет ваш любимый "кошерный STL-путь" для загрузки файла символов Unicode в wstring?
Что мне здесь не хватает; это должно быть что-то глупое.
Крис