【问题标题】:C++ Load binary file in memory and get the objectsC++ 在内存中加载二进制文件并获取对象
【发布时间】:2015-12-15 14:49:40
【问题描述】:

我有一个二进制文件,我在其中保存了数百万次以下变量:

  • x 大小的浮点向量
  • 两个无符号整数

目前我正在使用 ifstream 来打开和读取文件,但我想知道是否可以通过将整个文件加载到内存中并减少 I/O 来加快执行时间。

如何将文件加载到内存中,然后将其转换为我想要的变量?使用 ifstream 可以轻松完成,但我不知道如何对其进行缓冲然后提取数据。

这是我用来保存数据的代码:

osfile.write(reinterpret_cast<const char*> (&sz), sizeof(int));// Size of vector
osfile.write(reinterpret_cast<const char*> (&vec[0]), sz*sizeof(float));
osfile.write(reinterpret_cast<const char*> (&a), sizeof(unsigned int));
osfile.write(reinterpret_cast<const char*> (&b), sizeof(unsigned int));

【问题讨论】:

  • 前一周有人问了一个类似的问题,我想归结为使用ifstream#rdbuf,我看看能不能找到问题。
  • 我见过类似的问题,将文件作为字符数组获取。但是我应该如何从这个数组中读取变量呢?
  • 这个向量大小是固定的,还是每个向量都不同?
  • 人们,请停止做这样的事情:“osfile.write(reinterpret_cast (&vec[0]), vec.size()*sizeof(float));”使用适当的序列化范例,不要编写 blob。 Blob 容易出错,而且不安全。
  • 向量是固定大小的,我知道向量的大小,因为文件中保存的第一件事是一个 int,它是向量的大小。即使我有这样一个特定的文件也有问题吗?

标签: c++ buffer binaryfiles ifstream


【解决方案1】:

我猜您的写入过程中缺少某些内容,因为您的写入流中缺少向量的大小...

size_t size = vec.size();
osfile.write(reinterpret_cast<const char*> (&size), sizeof(size_t));
osfile.write(reinterpret_cast<const char*> (&vec[0]), vec.size()*sizeof(float));

osfile.write(reinterpret_cast<const char*> (&i), sizeof(unsigned int));
osfile.write(reinterpret_cast<const char*> (&i), sizeof(unsigned int));

然后你可以将全局文件缓冲区加载到内存中: Read whole ASCII file into C++ std::string

然后,将加载的缓冲区传递给istringstream iss; 对象

然后,以与编写流相同的方式读取流(流方法):

float tmp;
size_t size_of_vector;
// read size of vector
iss >> size_of_vector;
// allocate once
vector<float> vec(size_of_vector);
// read content
while(size_of_vector--)
{
    iss >> tmp;
    vec.push_back(tmp);
}
// at the end, read your pair of int
unsigned int i1,i2;
iss >> i1;
iss >> i2;

编辑:在打开/读取流时,您仍然需要注意二进制与字符的考虑...

【讨论】:

  • 写二进制和读文本可能不太好。
  • 当然,这就是我编辑的原因。这也取决于编码、印度性等。好吧,问题也与速度有关。关于这一点:由于流不是线程安全的,因此这是唯一有效的线索。
  • 感谢您的回答。向量的大小是固定的,并以 int 形式保存在文件中。使用这个 int 我分配了向量所需的空间。不会将文件作为字符串加载然后编号很慢吗?我想知道是否可以在不转换的情况下使用二进制文件
  • 问题是您建议的阅读代码与您建议的编写代码根本不兼容。
【解决方案2】:

这是我建议的方法。首先,将整个文件读入缓冲区:

std::ifstream binFile("your_binary_file", std::ifstream::binary);
if(binFile) {
    // get length of file
    binFile.seekg(0, binFile.end);
    size_t length = static_cast<size_t>(binFile.tellg());
    binFile.seekg(0, binFile.beg);

    // read whole contents of the file to a buffer at once
    char *buffer = new char[length];
    binFile.read(buffer, length);
    binFile.close();

    ...

然后,使用这种方法提取向量和整数:

    size_t offset = 0;
    int vectorSize = *reinterpret_cast<int*>(buffer);
    offset += sizeof(int);

    float *vectorData = reinterpret_cast<float*>(buffer + offset);
    std::vector<float> floats(vectorSize);
    std::copy(vectorData, vectorData + vectorSize, floats.begin());
    offset += sizeof(float) * vectorSize;

    int i1 = *reinterpret_cast<int*>(buffer + offset);
    offset += sizeof(int);
    int i2 = *reinterpret_cast<int*>(buffer + offset);

最后,当所有数据都读完后,别忘了删除为缓冲区分配的内存:

    delete[] buffer;
}

【讨论】:

  • 感谢您的回答。我目前使用 Cereal 并序列化对象。你认为你的方法会更快吗?从 ifstream 序列化我没有得到更好的执行时间。
  • @TheShadow 是的,我认为如果你做很多小负载会更快。
猜你喜欢
  • 2018-05-27
  • 2021-05-09
  • 2015-10-16
  • 2011-08-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多