-2

我有这个要序列化的类:(私有属性)

class Task {
    public:
        enum Status { COMPLETED, PENDIENT };
        // GETTERS SETTERS... 
        // UTILS
        const std::ostream& storeTask( std::ostream &stream );
        const std::istream& retrieveTask( std::istream &stream );
private:
        void setID();
        static int sCount;
        int id;
        std::string text;
        Status status;
        tm timestamp;
};

正如你所看到的,我试图通过实现我定义的一个storeTaskandretrieveTask方法来做到这一点:

// SERIALIZATION
const std::ostream& Task::storeTask( std::ostream &stream ) {
  stream.write((char *) &id, sizeof(int));
  stream.write((char *) text.c_str(), sizeof(text.length()));
  stream.write((char *) &status, sizeof(Status));
  stream.write((char *) &timestamp, sizeof(tm));
  return stream;
}
const std::istream& Task::retrieveTask( std::istream &stream ) {
  stream.read((char *) &id, sizeof(int));
  stream.read((char *) text.c_str(), sizeof(text.length()));
  stream.read((char *) &status, sizeof(Status));
  stream.read((char *) &timestamp, sizeof(tm));
  return stream;
}

我正在通过创建一个包含 2 个任务对象的向量来测试实现,使用它们的 storeTask 方法编写它们,然后创建另一个包含 2 个不同任务的任务向量,并尝试将第一个任务向量的值重新加载到第二个向量。

用这两个任务编写二进制文件似乎工作得很好,但是当再次读取它们时,它只获取文本字符串的前 4 个字符。

int main() {
        std::vector<Task> myTasks;
        Task task1("First Task");
        Task task2("Second Task");
        myTasks.push_back(task1);
        myTasks.push_back(task2);

        std::vector<Task> myTasks2;
        Task task3("Task num1");
        Task task4("Task num2");
        myTasks2.push_back(task3);
        myTasks2.push_back(task4);

        writeTasks(myTasks);
        readTasks(myTasks2);

    return 0;
}

void writeTasks(std::vector<Task> aTasks) {
        std::fstream fileStream("fileStream", std::ios::out | std::ios::binary);
        for ( int x = 0; x < aTasks.size(); x++ ) {
            std::cout << "Storing: " << aTasks[x].getText() << "\n";
            aTasks[x].storeTask(fileStream);
        }
        fileStream.close();
}
void readTasks(std::vector<Task> aTasks) {
        std::fstream fileStream;
        fileStream.open("fileStream", std::ios::in | std::ios::binary);
        for ( int x = 0; x < aTasks.size(); x++ ) {
            std::cout << "Retrieving " << aTasks[x].getText();
            aTasks[x].retrieveTask(fileStream);
            std::cout << " as --> " << aTasks[x].getText() << " - " << aTasks[x].getTime() << "\n";
        }
        fileStream.close();
}

这会返回:

Storing: First Task
Storing: Second Task
Retrieving Task num1 as --> Firs num1 - 01:02:26
Retrieving Task num2 as --> Seco num2 - 01:02:26

什么时候应该返回:

Storing: First Task
Storing: Second Task
Retrieving Task num1 as --> First Task - 01:02:26
Retrieving Task num2 as --> Second Task - 01:02:26

有任何想法吗?不知道问题是在编写二进制序列化还是读取它......其他值,如时间,日期似乎工作正常。

作为text.c_str()返回 a const char *,我声明了一个小函数来从字符串转换为 char *:

char * str_to_char(std::string s) {
    char *a=new char[s.size()+1];
    a[s.size()]=0;
    memcpy(a,s.c_str(),s.size());
    return a;
}

并在 retireveTask 方法中尝试了这个:

stream.read(str_to_char(text), text.size() + 1);

但得到:

Storing: First Task
Storing: Second Task
Retrieving Task num1 as --> Task num1 - 589824:524288:131072
Retrieving Task num2 as --> Task num2 - 112:09:08
4

1 回答 1

3

你有两个主要问题:

  1. 写的时候写sizeof(text.length()))。该运算符返回返回的sizeof大小(通常为 4 或 8 个字节)。仅使用.std::string::size_typetext.length()text.length()

  2. 阅读时,您尝试阅读直接放入字符串中的文本。这绝对不会起作用,因为甚至可能没有分配实际的字符串,或者没有分配足够的空间。我会说你很幸运,你能读到一些东西,你的程序不会在这里崩溃。

要序列化一个字符串(或任何可变大小的数据),您需要先存储字符串的长度,这样您就知道以后要读取多少。

正确的序列化并不容易,我真的建议您研究Boost 序列化,它可以正确处理所有奇怪和极端情况。

于 2012-10-08T05:19:23.327 回答