C ++使用起点和终点读取文件的特定部分

C++ Read specific parts of a file with start and endpoint

我正在序列化多个对象并想将给定的字符串保存到一个文件中。结构如下:

一些字符串和长属性,然后是可变数量的 maps<long, map<string, variant> >。我的第一个想法是创建一个有效的 JSON 文件,但这很难做到(所有地图都非常大,我的临时内存不够大)。由于我无法将所有内容连载在一起,因此我必须逐个进行。我打算这样做,然后我想将收到的字符串保存到一个文件中。这是它的样子:

{ "Name": "Whosebug"}
{"map1": //map here}
{"map2": //map here}

如您所见,这不是一个有效的 JSON 对象,而是一个文件中的 3 个有效的 JSON 对象。现在我想反序列化,我需要给反序列化器一个有效的 JSONObject 。每次我将一个新的 JSON 对象写入文件时,我已经保存了 tellp(),所以在这个例子中我将保存以下地址:26,endofmap1,endofmap2。

这是我想要做的:我想使用这些地址,从我写入的文件中提取字符串。我需要一个从 0 到 (26-1) 的字符串,一个从 26 到 (endofmap1-1) 的字符串和一个从 endofmap1 到 (endofmap2-1) 的字符串。由于这些字符串是有效的 JSONObjects 我可以毫无问题地反序列化它们。

我该怎么做?

我会创建一个 serializedeserialize class,您可以将它们用作层次结构的一部分。

例如,在粗略的 C++ 伪代码中:

class Object : public serialize, deserialize {
public:
    int a;
    float b;
    Compound c;

    bool serialize(fstream& fs) {
      fs << a;
      fs << b;
      c->serialize(fs);
      fs->flush();
    }
    // same for deserialize
};

class Compound : serialize, deserialize {
public:
  map<> things;
  bool serialize(fstream& fs) {
    for(thing : things) {
      fs << thing;
    }
    fs->flush();
  }
};

有了这个,您可以使用 JSON,因为文件将在您遍历层次结构时写入。

更新:

要从文件中提取特定字符串,您可以使用类似这样的方法:

// pass in an open stream (streams are good for unit testing!)
std::string extractString(fstream& fs) {
int location = /* the location of the start from file */;
int length = /* length of the string you want to extract */;
std::string str;
str.resize(length);
char* begin = *str.begin();

fs->seekp(location);
fs->read(begin, length);

return str;
}

根据你说的 "my temporary memory is not big enough",我将假设两种可能性(虽然某种代码示例可能会帮助我们帮助你!)。

可能一,文件太大

您在这里面临的问题不是新问题 - 文件太大而无法存储,假设您的算法没有缓冲所有数据,并且您的堆栈当然可以处理递归。

在 windows 上您可以使用 MapViewOfFile function, the MSDN has plenty of detail on that。此函数将有效地抓取文件的一部分 "view" - 允许您加载足够的文件以仅修改您需要的内容,然后在稍后的偏移处关闭和打开视图。

如果你在不同的平台,会有类似的功能。

可能性二,你一次做的太多了 另一个选项更像是一个 "software engineering" 问题。你有这么多数据,然后将它们保存在 std::maps 中时,你 运行 堆内存不足。

如果是这种情况,您将需要使用一些聪明的想法 - 这里有一些想法!

  1. 不要将所有数据加载到地图中。无论数据来自何处,都获取数据源的 CRC、索引或文件名。将该信息存储在地图中,并将实际的 "big strings" 保留在硬盘上。 - 这样您就可以在需要时加载每个 item 数据。

这对于需要排序或关联的数据非常有效。

  1. 在需要写入数据时处理或加载数据。如果您不需要对数据进行排序或关联,为什么要预先将其加载到地图中呢?只需按顺序加载每个 "big string" 数据,然后使用 ofstream 将它们写入文件。