[英]Saving a C struct with a char* string into a file
我正在嘗試將帶有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;
}
PS:我沒有使用STREAM函數,因為這實際上是指在沒有它們的嵌入式操作系統上運行。 我剛剛調整了* BSD / Linux的代碼,所以在提問時更有意義。
我知道可移植性不是問題,因為您正在為嵌入式系統工作。 在其他情況下,您應該使用類似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;
序列化永遠不會很好。 如何在字符串中存儲字符串的長度,並讓字符串跟隨文件中的結構? 這樣的事情(警告,腦編譯代碼):
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;
}
這里的問題實際上是一個更大問題的症狀:你不應該在內存和文件之間讀/寫二進制數據結構。 不僅沒有明確的方法來讀取/寫入帶有指向其他數據的結構(這不僅適用於字符串,還適用於嵌套數據,鏈接列表等),但磁盤上數據的格式取決於您的主機和C實現,不會移植到其他環境。
相反,您應該為磁盤上的數據設計格式並編寫函數來保存和加載數據,或者使用現有格式並查找庫代碼以使用它。 這通常被稱為“序列化”。
如果您的數據是分層的,則JSON,XML或EBML可能是合適的。 如果它相當簡單,平面文本文件或自制二進制格式(逐字節寫入,因此它是可移植的)可能是合適的。
由於您似乎不熟悉這些問題,因此在嘗試為自己的數據設計某些內容之前,編寫一些代碼來加載/保存一些簡單的二進制文件格式(如.tga或.wav)作為練習可能是值得的。
既然我知道你的問題的本質,為什么不嘗試靈活的數組呢? 而不是使用char *filename;
,使用char filename[1]
和malloc(sizeof struct d_object + filename_len)
來分配你的結構。 添加尺寸構件,可以很容易地寫入對象的磁盤與單個調用write
以及從與2個呼叫磁盤加載(第一讀取大小元件,第二分配之后讀取整個對象)。
請注意,在C99中執行靈活數組的“官方”方式是[]
而不是[1]
,但[1]
保證可以作為標准中其他要求的結果,也適用於C89。 [1]
會浪費幾個字節,所以如果您的編譯器支持[]
您可能想要使用它。
不,沒有直接用語言構建的魔法來為你做這件事。
您需要做的是編寫幾個函數將數據轉換為可寫形式,並從文件中讀回。 這被稱為“序列化”/“反序列化”的語言,使其更加大驚小怪。
您的特定結構,您可以執行某些操作,例如直接從結構中將二進制文件寫入文件,然后使用字符緩沖區的內容進行跟進。 如果在字符數據之前加上指定其長度的int
則可以使自己更容易讀取時間。
當你讀回那些東西時,你會想要malloc
/ calloc
自己一塊內存來保存char數據; 如果您存儲了大小,您將知道制作該malloc的大小。 將二進制數據讀入結構,將char數據讀入malloc內存,將指向malloc chunk的指針存儲到結構中,然后重新創建原始數據。
沒有魔法。 只是數據和一點肘部油脂。
編輯
當我寫這篇文章時,托馬斯編寫了一個例子。 我認為我們的答案很好地相互補充; 他們應該一起告訴你需要知道的一切。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.