我正在尝试将带有char *字符串的结构保存到文件中。
struct d_object {
int flags;
int time;
int offset;
char *filename;
};
问题在于,当我这样做时,我显然只会保存该指针的地址而不是字符串。所以我所做的只是使用一个字符数组,但我被迫设置字符串的最大大小。这工作正常,但我想知道是否有任何存储结构与文件中的char *(我在某些时候malloc),然后检索它。我可以保存字符串和结构分开,然后检索它们,但它是相当混乱。如果我可以将整个结构(上面的结构)加载并保存到文件中,那将是更好的选择。谢谢!
char数组的代码如下:
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
struct d_object {
int flags;
int time;
int offset;
char filename[255];
};
int main(int argc, char **argv) {
struct d_object fcb;
fcb.flags=5;
fcb.time=100000;
fcb.offset=220;
strncpy(fcb.filename,"myfile",255);
int fd=open("testfile",O_RDWR);
write(fd,&fcb,sizeof(fcb));
close(fd);
int fd2 = open("testfile",O_RDONLY);
struct d_object new_fcb;
read(fd2,&new_fcb,sizeof(new_fcb));
printf("read from file testfile: %s\n",new_fcb.filename);
return 0;
}
P.S。:我没有使用STREAM函数,因为这实际上是在没有它们的嵌入式操作系统上运行。我刚刚调整了* BSD / Linux的代码,所以在提问时更有意义。
答案 0 :(得分:7)
我知道可移植性不是问题,因为您正在为嵌入式系统工作。在其他情况下,您应该使用类似XML的东西。
您可以将代码转换回:
struct d_object {
int flags;
int time;
int offset;
char * filename;
};
然后单独保存每个数据:
write( fd, &record.flags, sizeof( int ) );
write( fd, &record.time, sizeof( int ) );
write( fd, &record.offset, sizeof( int ) );
int filename_length = strlen( filename );
write( fd, &filename_length, sizeof( int ) );
write( fd, record.filename, filename_length );
对于阅读,你必须分开阅读每个项目,然后是文件名:
int filename_length;
read( fd, &emptyRecord.flags, sizeof( int ) );
read( fd, &emptyRecord.time, sizeof( int ) );
read( fd, &emptyRecord.offset, sizeof( int ) );
read( filename_length, sizeof( int ), 1, file );
emptyRecord.filename = (char *) malloc( sizeof( char ) * ( filename_length +1) );
read( fd, emptyRecord.filename, filename_length );
*( emptyRecord.filename + filename_length ) = 0;
答案 1 :(得分:2)
序列化永远不会很好。如何在字符串中存储字符串的长度,并让字符串跟随文件中的结构?这样的事情(警告,脑编译代码):
void write_object(struct d_object *s, int fd) {
struct d_object copy = *s;
copy.filename = (char*)strlen(s->filename);
write(fd, ©, sizeof(copy));
write(fd, s->filename, (size_t)copy.filename);
}
void read_object(struct d_object *s, int fd) {
read(fd, s, sizeof(struct d_object));
char *filename = malloc(((size_t)s->filename) + 1);
read(fd, filename, (size_t)s->filename);
filename[(size_t)s->filename] = '\0';
s->filename = filename;
}
答案 2 :(得分:2)
这里的问题实际上是一个更大问题的症状:你不应该在内存和文件之间读/写二进制数据结构。不仅没有明确的方法来读取/写入带有指向其他数据的结构(这不仅适用于字符串,还适用于嵌套数据,链接列表等),但磁盘上数据的格式取决于您的主机和C实现,不能移植到其他环境。
相反,您应该为磁盘上的数据设计一种格式,并编写函数来保存和加载数据,或使用现有格式并查找库代码以便使用它。这通常被称为“序列化”。
如果您的数据是分层的,则JSON,XML或EBML可能是合适的。如果它相当简单,平面文本文件或自制二进制格式(逐字节写入,因此它是可移植的)可能是合适的。
由于您似乎不熟悉这些问题,因此在尝试为您设计一些内容之前,编写一些代码来加载/保存一些简单的二进制文件格式(如.tga或.wav)作为练习可能是值得的。自己的数据。
答案 3 :(得分:2)
现在我知道你的问题的本质,为什么不尝试灵活的数组呢?不要使用char *filename;
,而是使用char filename[1]
和malloc(sizeof struct d_object + filename_len)
来分配您的结构。添加一个size成员,只需调用write
就可以轻松地将对象写入磁盘,并通过2次调用从磁盘加载它(首先读取size元素,然后在分配后读取整个对象)
请注意,在C99中执行灵活数组的“官方”方式是[]
而不是[1]
,但[1]
可以保证在标准和其他要求的后果下工作也适用于C89。 [1]
会浪费几个字节,所以如果您的编译器支持[]
,您可能想要使用它。
答案 4 :(得分:1)
不,没有直接在语言中构建魔法来为你做这件事。
您需要做的是编写几个函数将数据转换为可写形式,并从文件中读回。这种语言被称为“序列化”/“反序列化”,而这些语言对此更加轻松。
你的特定结构,你可以做一些事情,比如直接从结构中将二进制文件写入文件,然后用字符缓冲区的内容跟进。如果您在字符数据之前加上指定其长度的int
,则可以让自己更容易上手。
当你重读这些东西时,你会想要malloc
/ calloc
自己一块内存来保存char数据;如果您存储了大小,您将知道制作该malloc的大小。将二进制数据读入struct,将char数据读入malloc内存,将指向malloc chunk的指针存储到struct中,然后重新创建原始数据。
没有魔力。只是数据和一点肘部油脂。
修改强>
当我写这篇文章时,托马斯编写了一个例子。我认为我们的答案很好地相互补充;他们应该一起告诉你需要知道的一切。