поиск и внедрение в wifstream работают неправильно

#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,5 wchar_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:

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=15733