Как я могу записать структуру в файл?

Я пытался найти это в нескольких местах, и я не могу понять, почему fwrite не работает.

Если бы у меня была структура с 100 полями, я бы не хотел использовать fprintf со 100 спецификаторами формата.

struct emp
{
      char name[15];
      int age;
      int salary;
      char address[30];
};


int main()
{

    char str[60];
    struct emp emp1[5] = {{"Yoda",23,45000,"Asia"},{"Darth",34,2344,"NAmerica"},{"Jabba",22,5566,"Africa"},{"Luke",33,3399,"SAmerica"},{"Laya",44,6677,"Europe"}};

    FILE *fp;
    fp = fopen("C:/.../sampleText.txt","w");`
    int i=0;
   for(i=0; i<5; i++)
   {

            fwrite(&emp1[i],sizeof(emp1[i]),1,fp);

           //fprintf(fp,"%s, %d, %d, %s\n",&emp1[i].name,emp1[i].age,emp1[i].salary,emp1[i].address);
    }

    fclose(fp);
    getch();
 }

4 ответа

Решение

Есть два ответа:

  1. Это работает, если все настроено правильно, и перенос записанных данных на другие машины не является проблемой.
  2. Это не работает, если у вас есть какие-либо из большого количества общих функций в структурах данных или если вам нужно переместить данные с одного типа машины (скажем, машины Intel) на другой тип (например, PowerPC или SPARC).

В вашем примере структуры у вас нет указателей, так что вы можете записать дословно структуру в файл, а затем при другом вызове программы, запущенной на том же (типе) компьютере, вы можете прочитать ее обратно и увидеть одни и те же данные.

Однако, если ваша структура содержит указатели, вы не сможете осмысленно записать структуру на диск. Указатели в одном вызове программы не должны иметь никакого значения в другом вызове программы. Если вам нужно перенести данные между машиной с прямым порядком байтов (Intel) и машиной с прямым порядком байтов (PowerPC, SPARC), вам придется использовать независимый от платформы способ доступа к данным; просто запись данных на диск не будет работать.


Таким образом, если переносимость не является проблемой, этот код должен работать - Unix или Windows. Он использует "wb" а также "rb" аргументы fopen() потому что данные являются двоичными данными, а не простым текстом. b необязателен, но безвреден для Unix; это важно для Windows. Код также исправляет имя файла в sampledata.bin поэтому его можно запускать на любой платформе, записывая в текущий каталог. Пишет данные; затем он читает данные; Затем он сравнивает прочитанные данные с записанными данными, сообщая о любых проблемах. Если программа ничего не говорит, все в порядке.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct emp
{
    char name[15];
    int age;
    int salary;
    char address[30];
};

int main(void)
{
    char const filename[] = "sampledata.bin";
    struct emp emp1[5] =
    {
        { "Yoda",  23, 45000, "Asia"      },
        { "Darth", 34,  2344, "N America" },
        { "Jabba", 22,  5566, "Africa"    },
        { "Luke",  33,  3399, "S America" },
        { "Leia",  44,  6677, "Europe"    },
    };
    struct emp emp2[5];
    FILE *ifp;
    FILE *ofp;
    int i;

    ofp = fopen(filename, "wb");
    if (ofp != 0)
    {
        if (fwrite(emp1, sizeof(emp1), 1, ofp) != 1)
        {
            fprintf(stderr, "Failed to write to %s\n", filename);
            exit(1);
        }
        fclose(ofp);
    }

    ifp = fopen(filename, "rb");
    if (ifp != 0)
    {
        if (fread(emp2, sizeof(emp2), 1, ifp) != 1)
        {
            fprintf(stderr, "Failed to read from %s\n", filename);
            exit(1);
        }
        fclose(ifp);
    }

    for (i = 0; i < 5; i++)
    {
        if (emp1[i].age != emp2[i].age ||
            emp1[i].salary != emp2[i].salary ||
            strcmp(emp1[i].name, emp2[i].name) != 0 ||
            strcmp(emp1[i].address, emp2[i].address) != 0)
            printf("Difference in record %d\n", i);
    }

    return 0;
}

Содержание файла sampledata.bin:

0x0000: 59 6F 64 61 00 00 00 00 00 00 00 00 00 00 00 00   Yoda............
0x0010: 17 00 00 00 C8 AF 00 00 41 73 69 61 00 00 00 00   ........Asia....
0x0020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................
0x0030: 00 00 00 00 00 00 00 00 44 61 72 74 68 00 00 00   ........Darth...
0x0040: 00 00 00 00 00 00 00 00 22 00 00 00 28 09 00 00   ........"...(...
0x0050: 4E 20 41 6D 65 72 69 63 61 00 00 00 00 00 00 00   N America.......
0x0060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................
0x0070: 4A 61 62 62 61 00 00 00 00 00 00 00 00 00 00 00   Jabba...........
0x0080: 16 00 00 00 BE 15 00 00 41 66 72 69 63 61 00 00   ........Africa..
0x0090: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................
0x00A0: 00 00 00 00 00 00 00 00 4C 75 6B 65 00 00 00 00   ........Luke....
0x00B0: 00 00 00 00 00 00 00 00 21 00 00 00 47 0D 00 00   ........!...G...
0x00C0: 53 20 41 6D 65 72 69 63 61 00 00 00 00 00 00 00   S America.......
0x00D0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................
0x00E0: 4C 65 69 61 00 00 00 00 00 00 00 00 00 00 00 00   Leia............
0x00F0: 2C 00 00 00 15 1A 00 00 45 75 72 6F 70 65 00 00   ,.......Europe..
0x0100: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................
0x0110: 00 00 00 00 00 00 00 00                           ........
0x0118:

Вы не указываете, что вы подразумеваете под fwrite doesn't work, но я предполагаю, что вы работаете на Windows, в этом случае вам нужно указать "wb" в fopen, По умолчанию в Windows пишет text mode (т.е. "wt").

Не очень хорошая идея писать struct к файлу или сокетам как есть. Это комплекс для решения проблем. лучший подход - использовать сериализацию перед записью. Также, как указал Джим выше, обязательно откройте файл в двоичном формате.

Посмотрите на этот вопрос и ответы. на ваш вопрос есть довольно хороший ответ и объяснение. Передача структуры через сокеты в C

Сериализация данных - нетривиальная задача. Как отмечали некоторые другие, в некоторых случаях возможно записать содержимое вашей структуры на диск в виде двоичных данных. Его проще всего написать, но вряд ли оно будет стабильным. Каждый раз, когда вы перекомпилируете свой код, он может потенциально изменить формат записи и чтения данных.

Лучше всего использовать стандартный формат обмена данными, такой как CSV, XML или JSON. Существует много существующих инструментов для использования этих форматов, поэтому вы должны рассмотреть возможность использования одного из них.

Другие вопросы по тегам