1

我需要读取一个包含标题和数据的二进制文件(一次性)。用 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);

这是没有 istreambuf_iterator 的 ifstream

char* Data = new char[Size];

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

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

/* ... */

delete[] Data;

这是带有 istreambuf_iterator 的 ifstream

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());
4

3 回答 3

3

将文件的内容读入 achar*然后执行reinterpret_casttoHeaderType*不是一个好主意。

从标准:

5.2.10 重新解释演员表

...

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

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

如果你有选择,我会建议。

  1. 首先阅读标题。

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

于 2015-03-12T17:08:31.180 回答
1

这将是“基于意见的”,因此对于 SO 来说并不是严格意义上的。

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

但是,更重要的是,您这样做的方式违反了严格的别名规则,因为您的内存中的对齐方式struct不能保证与char数组一致。

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

HeaderType header;

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

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

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

于 2015-03-12T17:04:00.897 回答
0

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

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

记录一下:使用系统级函数会将数据直接从操作系统传输到缓冲区。 istream::read将从中的内部缓冲区复制filebuf到缓冲区中(并使用系统级函数将数据获取到缓冲区中)。另外两个将std::string逐字节构建一个对象,根据需要分配内存,因为最终长度是未知的。

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

于 2015-03-12T18:50:36.987 回答