Размер файла Fstream в кодовых точках

Существует много вопросов о получении размера файла в файле std :: fstream, но все они возвращают размер файла в байтах и ​​подвержены ошибкам, если файл открыт в другом потоке.

Я хочу знать размер файла в кодовых точках, а не в байтах.

Сейчас std::fstream::seekg(0,std::ios::end) с последующим std::fstream::tellg() возвращает только длину в байтах. Это не говорит мне, сколько символов UTF-16/32 находится в файле. Разделите результат на sizeof(wchar_t) Я слышу, как ты говоришь. Не работает для файлов UTF-8 и НЕ является переносимым.

Теперь, для более технических единомышленников, у меня есть imbued поток с моим собственным std::codecvt учебный класс. std::codecvt имеет члена length() который, учитывая два указателя в потоке, вычисляет длину и возвращает максимальное или количество выходных символов. Я бы подумал, что поиск по файлу будет искать по codecvt::intern_type а не по основанию char тип.

Я посмотрел в fstream заголовок и обнаружил, что искать Infact не использует codecvt, И, на моей версии от VS2010, codecvt::length() член даже не упоминается. Infact, при каждом звонке codecvt::in(), новый строковый объект создается и увеличивается в размере на 1 символ каждый раз in() возвращается partial, Вместо этого он не вызывает codecvt::max_length() участник и снабдить вызов адекватным буфером.

Это просто моя реализация или я могу ожидать, что другие будут делать то же самое? имеет std::fstream был переписан для VS2012, чтобы в полной мере использовать локали?

По сути, мне надоело писать собственные обработчики файлов каждый раз, когда я использую текстовые файлы. Я надеюсь создать fstream производный класс, который будет сначала читать файлы спецификации, если они есть, и наполнять codecvt, Затем преобразовать эти символы в char, wchar_t или как того требует код. Я также надеюсь закодировать его таким образом, чтобы, если известно предварительное знание кодировки, locale можно указать на строительстве.

Буду ли я лучше работать непосредственно с внутренним буфером, перезаписывать аффект класса fstream или есть какие-то хитрости, о которых я не знаю?

0

Решение

Если я вас правильно понимаю, вы ожидаете, что:

`std::basic_fstream<CharT,Traits>::seekg`

(который по наследству basic_istream<CharT,Traits>::seekg), должен
выполнить операцию позиционирования потока в единицах, которые являются
intern_type из чего угодно codecvt которым пропитан поток.

шаблон basic_istream объявлено:

template<
class CharT,
class Traits = std::char_traits<CharT>
> class basic_istream;

В объявлении функции-члена:

basic_istream & basic_istream<CharT,Traits>::seekg(pos_type pos)

pos_type является std::char_traits<CharT>::pos_type который поэтому
тип определяется в любой реализации исключительно CharT шаблон
аргумент basic_istream класс и без ссылки на любой codecvt,

basic_fstream<char>например, остается basic_fstream<char>,
И его pos_type остатки basic_fstream<char>::pos_type,
независимо от кодировки, выбранной для чтения или записи.

Приведенные выше объявления соответствуют стандарту C ++ 11 § 27.7.1.
и § 27.7.2.1. Дело в том, что pos_type инвариантен с
уважение к любому проникнутому codecvtи, следовательно, также поведение seekg(pos_type),
следовательно, являются последствиями стандарта.

Эквивалентные замечания применяются для basic_istream& seekg( off_type off, std::ios_base::seekdir dir),

std::codecvt::intern_type это тип элементов внутреннего
последовательность, в которую или из которой будет указана кодировка
перевести внешнюю последовательность элементов типа extern_type,
intern_type тип элемента последовательности «в программе» и
extern_type тип последовательности «в файле» intern_type
не имеет ничего общего с операциями позиционирования файла.

если ты должен узнать размер файла в кодовых точках и предположить
что возможные представляющие интерес кодировки UTF-8, UTF-16 и UTF-32, то
для первых двух из них у вас нет выбора, кроме как прочитать весь файл,
потому что они являются кодировками переменной длины, с кодовой точкой UTF-8, потребляющей
1-4 байта и кодовая точка UTF-16, занимающая 2 или 4 байта. UTF-32 является
4-байтовое кодирование фиксированной длины, поэтому в этом случае вы можете вычислить число
полные кодовые точки в виде байтовой длины файла, минус длина спецификации, если есть,
делится на 4, если вы исключаете возможность ошибок кодирования, кроме конца файла.

Для кодировок переменной длины самый простой способ подсчета
кодовые точки будут с функцией шаблона, параметризованной
индикатор предполагаемой кодировки. Сначала он прочитает файл
использование спецификации, если есть, в единицах char или же char16_t при необходимости,
идентифицируя каждую единицу, которая является ведущим элементом кодовой точки в
предполагаемое кодирование; проверка наличия номера последующего
элементы, необходимые для ведущего элемента, и увеличение счетчика кодов
если они найдены.

2

Другие решения

length функция std::char_traits возвращает количество CharTсимволы, которые не обязательно являются количеством байтов. Так что в основном вам нужно прочитать буфер вашего файла в std::string и распечатать его size():

std::ofstream out("out.txt");
out.rdbuf()->pubimbue(std::locale("en_US.UTF8"));

std::streambuf* p = out.rdbuf();
p->pubseekoff(0, std::ios_base::beg);

std::string data; //  use std::u16string for UTF-16 data

data.assign(std::istreambuf_iterator<char>(out),
std::istreambuf_iterator<char>());

std::cout << "We have " << data.size() << " codepoints";
0