关于获取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
。然后将这些字符转换为char
,wchar_t
或代码所要求的任何内容。我也希望以这样的方式对其进行编码:如果已知编码的先验知识,则可以在构造时指定locale
。
我会更好地直接在内部缓冲区工作,影响重写fstream类,还是有一些我不知道的技巧?
答案 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_type
或char
为单位消费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";