#c #c 11 #locale #wifstream
#c #c 11 #язык #wifstream
Вопрос:
У меня есть файл, подобный приведенному ниже:
$ xxd 1line
0000000: 3939 ba2f 6f20 6f66 0d0a 99./o of..
Я хотел бы прочитать эту строку на C :
#include <codecvt>
#include <iostream>
#include <locale>
#include <fstream>
#include <string>
int main(int argc, char** argv) {
std::wifstream wss(argv[1], std::ios::binary);
wss.seekg(std::ios_base::end);
const auto fileSize = wss.tellg();
wss.seekg(std::ios_base::beg);
// std::locale utf8_locale(wss.getloc(), new std::codecvt_utf8<wchar_t, 0x10FFFF, std::consume_header>);
// wss.imbue(utf8_locale);
std::wstring wline;
std::getline(wss, wline);
std::cout << "filelen: " << fileSize << std::endl;
std::cout << "strlen: " << wline.size() << std::endl;
std::wcout << "str: " << wline << std::endl;
return 0;
}
Я компилирую его следующим образом:
$ g -std=c 11 imbue_issue.cpp
Первое: кажется, что wss.seekg(std::ios_base::end) не перемещает позицию файла в конце файла:
$ ./a.out 1line
filelen: 2
strlen: 9
str: 99?/o of
Во-вторых, при раскомментировании строк, связанных с локализацией, getline считывает только 2 символа:
$ ./a.out 1line
filelen: 2
strlen: 2
str: 99
Мой компилятор:
$ g --version
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk/usr/include/c /4.2.1
Apple LLVM version 7.3.0 (clang-703.0.31)
Target: x86_64-apple-darwin15.6.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
Кто-нибудь знает, в чем причина возникновения вышеуказанных проблем с этим файлом?
Комментарии:
1. Каков размер
wchar_t
вашей системы? Держу пари, что это так4
. Это означает, что размер файла составляет 2,5wchar_t
символа, который усекается до2
.2. Да, это 4 байта.
3. Кроме того, судя по дампу содержимого файла, похоже, что это файл не с широкими символами, а с узкими символами. Попробуйте вместо этого использовать «обычный» narrow
char
и посмотрите, какие результаты вы получите.4. Забавно, когда я перешел с wifstream на ifstream, размер файла по-прежнему равен 2. Основан ли ifstream на char? Я проверил, что sizeof (char) в моей системе равен 1.
Ответ №1:
Проблема в том, как вы вызываете seekg
функцию. Когда вы вызываете его с одним аргументом, он используется как абсолютная позиция с самого начала, и вы будете искать любое значение std::ios::end
, которое есть 2
в вашем случае.
Вместо этого вы должны использовать перегрузку с двумя аргументами:
wss.seekg(0, std::ios_base::end); // Seek to offset 0 from the end
У вас все равно будут проблемы с чтением файла с использованием широкосимвольных типов, поскольку содержимое, похоже, таковым не является. UTF-8 — это многобайтовая узкая кодировка символов.
Комментарии:
1. Я понимаю, что проблема imbue связана с использованием wifstream вместо ifstream, верно? Существует ли какой-либо общий способ чтения файлов на C , если мы не знаем, что такое содержимое? Если нет, то как программно решить, нужен ли ifstream из wifstream?
2. @mkk Нет, на самом деле нет хорошего способа определить, как были сохранены данные или их кодировка, если только файл не имеет какого-либо заголовка или подобного, например, метки порядка байтов UTF- 8.
Ответ №2:
Я обнаружил, что у кого-то были похожие проблемы с getline: