2013-11-14 75 views
0

我正在尝试在文件中写入C结构(以二进制写入)并读取它以恢复它。我不知道这是否可能。 以下是我有:C++ - 如何编写和读取包含对象的结构? (写入和读取二进制文件)

head.hh:

#include <iostream> 

typedef struct s_test 
{ 
    char cmd[5]; 
    std::string str; 
}t_test; 

main.cpp中:

#include <stdlib.h> 
#include <sys/types.h> 
#include <sys/stat.h> 
#include <fcntl.h> 
#include "head.hh" 

int  main() 
{ 
    t_test  test; 
    int fd = open("test", O_APPEND | O_CREAT | O_TRUNC | O_WRONLY, 0666); 

    test.cmd[0] = 's'; 
    test.cmd[1] = 'm'; 
    test.cmd[2] = 's'; 
    test.cmd[3] = 'g'; 
    test.str = "hello world"; 
    write(fd, &test, sizeof(t_test)); 


    close(fd); 
    fd = open("test", O_APPEND | O_CREAT | O_WRONLY, 0666); 

    t_test  test2; 

    read(fd, &test2, sizeof(t_test)); 
    std::cout << test2.cmd << " " << test2.str << std::endl; 

    return (0); 
} 

和输出我有类似: Ȟ

+2

你不能以这种方式读/写一个'std :: string',你需要一次一个序列化数据。 –

+0

这不会在没有序列化的情况下工作 – drescherjm

+0

使用“基本”类型,这意味着,在结构中不是对象,然后你可以用char,int,float来做到这一点。如果你使用一个对象,你将无法得到真正的大小 – Lefsler

回答

1

要读取的文件被打开为只写。

实际std::string对象不能这样写。实际的对象通常包含一对指针,也许是一个大小,但不包含实际的字符数据。它需要被序列化。

如果你要编写C++,你应该考虑学习使用文件流而不是你在这里得到的。

#include <stdlib.h> 
#include <sys/types.h> 
#include <sys/stat.h> 
#include <fcntl.h> 
#include <io.h> 
#include <iostream> 
#include <string> 
#include <vector> 

typedef struct s_test 
{ 
    char cmd[5]; 
    std::string str; 
}t_test; 

void Write(int fd, struct s_test* test) 
{ 
    write(fd, test->cmd, sizeof(test->cmd)); 
    unsigned int sz = test->str.size(); 
    write(fd, &sz, sizeof(sz)); 
    write(fd, test->str.c_str(), sz); 
} 

void Read(int fd, struct s_test* test) 
{ 
    read(fd, test->cmd, sizeof(test->cmd)); 
    unsigned int sz; 
    read(fd, &sz, sizeof(sz)); 
    std::vector<char> data(sz); 
    read(fd, &data[0], sz); 
    test->str.assign(data.begin(), data.end()); 
} 

int main() 
{ 
    t_test test; 
    int fd = open("test", O_APPEND | O_CREAT | O_TRUNC | O_WRONLY, 0666); 

    test.cmd[0] = 's'; 
    test.cmd[1] = 'm'; 
    test.cmd[2] = 's'; 
    test.cmd[3] = 'g'; 
    test.cmd[4] = 0; 
    test.str = "hello world"; 
    std::cout << "Before Write: " << test.cmd << " " << test.str << std::endl; 

    Write(fd, &test); 
    close(fd); 

    fd = open("test", O_RDONLY, 0666); 
    t_test test2; 
    Read(fd, &test2); 
    std::cout << "After Read: " << test2.cmd << " " << test2.str << std::endl; 
    close(fd); 

    return (0); 
} 
+0

这是一个“二进制”协议吗? – Elfayer

+0

是的,这些字节就像它们在内存中一样被读取/写入。没有任何已经将文本翻译成文本的内容没有任何翻译。 –

+0

因为当我在一个文件中用char [4]写一个结构时,当我打开该文件时,我可以直接读取字符串。它在二进制文件中没有任何翻译。 – Elfayer

0

见当您将结构转储为二进制文件时,其内存映像会被写入磁盘,例如:

class X 
{ 
public: 
    int i; 
    int j; 
}; 

。 。 。

X lX; 
lX.i= 10; 
lX.j = 20; 

当写入二进制文件时,类lX的对象看起来像| 10 | 20 | 也就是说,当你阅读它会工作正常。

但是对于包含像string这样的任何指针的类。

class Y 
{ 
public: 
    int* pi; 
    int j; 
}; 

。 。 。

Y lY; 
lY.pi= new int(10); // lets assume this is created at memory location 1001 
lY.j = 20; 

所以对象lY的pi值为1001(不是10,因为它是一个指针)。现在,当您将lY写入二进制文件时,它将看起来像| 10001 | 20 |当你读到它时,它会构造Y的新对象(比如lY2),其值pi为1001,j为20.现在我们pi(它是一个指针)指向什么?答案是垃圾,这是你在屏幕上看的东西。我想你正在使用Windows来运行它,因为Linux会给你一个分段错误。

+0

所以你需要序列化字符串,使其可以是空终止或长度前置。 – Shubham