代码点中的fstream文件大小

时间:2013-07-17 04:48:16

标签: c++ locale fstream codecvt

关于获取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标头,发现seek infact不使用codecvt。而且,在我的VS2010版本中,甚至没有提及codecvt::length()成员。事实上,在每次调用codecvt::in()时,每次in()返回partial时,都会创建一个新的字符串对象并将其大小增加1个字符。它不会调用codecvt::max_length()成员并使用足够的缓冲区提供调用。

这只是我的实施还是我希望其他人也这样做?是否已为VS2012重写std::fstream以充分利用区域设置?

基本上,每次使用文本文件时,我都厌倦了编写自己的文件处理程序。我希望创建一个fstream派生类,它将首先读取文件BOM(如果存在),并填充正确的codecvt。然后将这些字符转换为charwchar_t或代码所要求的任何内容。我也希望以这样的方式对其进行编码:如果已知编码的先验知识,则可以在构造时指定locale

我会更好地直接在内部缓冲区工作,影响重写fstream类,还是有一些我不知道的技巧?

2 个答案:

答案 0 :(得分:2)

如果我理解你的话,你希望:

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

(继承是basic_istream<CharT,Traits>::seekg),应该 以单位为单位执行流定位操作 <{1}}所有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, 无论选择何种编码来读取或写入它。

上述声明分别符合C ++ 11标准§27.7.1 和§27.7.2.1。 basic_fstream<char>::pos_type不变的事实 尊重任何充满的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 与文件上的定位操作无关。

如果必须在代码点中找出文件的大小,并假定 可能的编码是UTF-8,UTF-16和UTF-32 对于前两个,你别无选择,只能阅读整个文件, 因为它们是可变长度编码,使用UTF-8代码点 消耗2或4个字节的1-4个字节和UTF-16代码点。 UTF-32是一个 固定长度的4字节编码,所以在这种情况下你可以计算数量 完整的代码点作为文件的字节长度,减去BOM长度(如果有的话), 如果你打算编码错误的可能性,除了在文件结束时,除以4。

对于可变长度编码,最简单的计数方法 代码点将使用参数化的模板函数 推测编码的指标。它将首先读取文件 以intern_typechar为单位消费BOM(如果有), 识别作为代码点的主要元素的每个单元 推测编码;验证后续数量的存在 lead元素所需的元素,并递增代码点计数 如果他们找到了。

答案 1 :(得分:0)

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";