簡體   English   中英

將帶有char *字符串的C結構保存到文件中

[英]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, &copy, 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM