ifstream与istreambuf_iterator之间的区别是什么?

时间:2015-03-12 16:52:08

标签: c++ ifstream istream-iterator

我需要读取包含标题和数据的二进制文件(一次性)。有不同的方法来读取C ++文件,我想知道哪一个是最快,更可靠的。我也不知道reintrerpret_cast是否是将原始数据转换为结构的最佳方式。

编辑:标题结构没有任何功能,只有数据。

ifstream File(Filename, ios::binary);    // Opens file

if (!File)    // Stops if an error occured
{
    /* ... */
}

File.seekg(0, ios::end);
size_t Size = File.tellg();    // Get size
File.seekg(0, ios::beg);

这是ifstream WITHOUT istreambuf_iterator

char* Data = new char[Size];

File.read(Data, Size);
File.close();

HeaderType *header = reinterpret_cast<HeaderType*>(Data);

/* ... */

delete[] Data;

ifstream with istreambuf_iterator

std::string Data;    // Is it better to use another container type?

Data.reserve(Size);
std::copy((std::istreambuf_iterator<char>(File)), std::istreambuf_iterator<char>(),
          std::back_inserter(Data));

File.close();

const HeaderType *header = reinterpret_cast<HeaderType*>(Data.data());

也在互联网上找到了这个

std::ostringstream Data;
Data << File.rdbuf();
File.close();
std::string String = Data.str();

const HeaderType *header = reinterpret_cast<HeaderType*>(String.data());

3 个答案:

答案 0 :(得分:3)

将文件内容读入char*然后执行reinterpret_castHeaderType*并不是一个好主意。

来自标准:

  

5.2.10重新解释投射

     

...

     

7可以将对象指针显式转换为不同类型 70 的对象指针。当“指向v的指针”的prvalue T1转换为“指向 cv T2的指针”时,结果为static_cast<cv T2*>(static_cast<cv void*>(v))如果T1T2都是标准布局类型(3.9),并且T2的对齐要求不比T1更严格,或者任何一种类型都是{{} 1}}。将“指向void”的类型的prvalue转换为“指向T1”的类型(其中T2T1是对象类型,{{T2的对齐要求1}}不比T2更严格,并且返回其原始类型会产生原始指针值。任何其他此类指针转换的结果都未指定。

在您的情况下,如果T1的对齐要求比HeaderType更严格,则会遇到未定义的行为。

如果您有选择,我建议。

  1. 首先阅读标题。

    char
  2. 根据HeaderType header; File.read(reinterpret_cast<char*>(&header), sizeof(HeaderType)); 的值阅读其余数据。

答案 1 :(得分:1)

这将是基于意见的&#39;因此对于SO来说并非严格意义上的。

但是,在这种情况下我没有看到使用迭代器的重点,因为read()函数更简洁。

然而,更重要的是,您执行此操作的方式会破坏严格的别名规则,因为struct内存中的对齐不能保证与char数组一致。

最好将struct的地址转换为char*,而不是相反:

HeaderType header;

File.read(reinterpret_cast<char*>(&header), sizeof(header));
File.close();

以这样的二进制方式读取数据是不可移植的,并且不适用于复杂的用户定义类型(如std::string),因此最好将所有数据成员序列化为格式化字符串。

注意:有关类型别名的信息,请参阅reinterpret_cast的文档。

答案 2 :(得分:0)

首先,您描述的解决方案都不会真正起作用;该 reinterpret_cast应该告诉你。在某些时候,你必须这样做 解析缓冲区中的字节,并插入提取的数据字段 字段到您的内部数据结构。

至于尽快将字节输入缓冲区, 你做的额外工作越少越好。最快的方法是 在Unix下使用低级IO(open然后read),甚至映射 将文件存入内存(Unix下为mmap)。当然,这是系统 依赖;如果你想使用ifstream来实现系统 独立性,然后使用istream::read肯定是最快的(和 最符合逻辑的,所有事情都考虑在内)。只要确定流 充满了"C"语言环境,以及以二进制模式打开。

对于记录:使用系统级功能将传输数据 直接从OS进入缓冲区。 istream::read将从中复制 filebuf中的内部缓冲区进入缓冲区(并使用系统 级别函数将数据输入缓冲区)。另外两个会 逐个字节地构建一个std::string对象,将内存分配为 需要,因为最后的长度将不知道。

最后,使用new char[size]而不是std::vector<char>