如何在C语言中将结构体保存到文件中

6

我想将一个结构体保存在文件中。我想实现一个函数来完成这个任务。我尝试了下面的代码,但它没有起作用。

struct utilisateur   // enregestrement pour sauvegarder les details de l utilisateur
{
 char nom[20];
 char prenom[20];
 int place;
 char depart[20];
 char arrive[20];
 char sexe;
 int nwagon;
};

struct utilisateur utilis;
struct utilisateur *Table[48];

void crea_fich(struct utilisateur *Tutilis)
// creation un fichier, vous introduiez le nom, et le sotcker par enreg
{
    FILE *f;
    if (f!==0)
    {
         printf("error in the name of file \n");
         exit(1);
    }
    if (f=fopen(futilis,"w")==Null){
         fprint("We can't creat file \n");
         exit(1);
    }
    else{
        f=fopen("futilis.dat","wb");
        fwrite(Tutilis ,sizeof(utilisateur),1,f);
    }
}

你的那段代码有很多噪音,更不用提格式问题了(并且Table的声明看起来很奇怪)。假设你的实际代码执行到fwrite那一步时,它的结果和你的期望有什么不同? - brendan
你好。你能在你的问题中加入一些文本格式吗?这样会使阅读更容易。 - user50685
你想用 "if (f!==0)" 做什么?首先,"f" 没有初始化,所以在那个点上使用它是错误的。其次,没有运算符 "!==";你应该使用 "!="。 - Michael Aaron Safyan
3
我很不想说这个,但你最好用英语编写代码,因为它是全球使用最广泛的语言,这样可以最大化能够帮助你或与你合作的人数。 - Michael Aaron Safyan
你想要以人类可读的方式编写结构体,还是只需要生成一份可能不可移植的机器可读输出呢? - caf
6个回答

6

仅供参考的简单示例 :)

// your struct
struct Data
{
    int first;
    double second;
    char third[10];
};

然后编写结构体!
struct Data data = {22, 4.0, "Hi"};
FILE* output;

output = fopen("Data.dat", "wb");

fwrite(&data, sizeof(data), 1, output);

fclose(output);

最后从你创建的文件中读取数据!

struct Data data;
FILE* input;

input = fopen("Data.dat", "rb");

fread(&data, sizeof(data), 1, input);

// you got the data from the file!

fclose(input);

二进制文件如果不明智地编写和读取,就会成为噩梦。您必须关注创建文件的体系结构以及将在哪里读取文件。大小端和变量大小是最重要的。此外,如果您的 struct 中有指针,则将写入文件的是指针而不是指针所指向的实际数据。抱歉,我没有编辑您的代码,因为它充满了编译错误 :)

这只是一个小问题,但你在“r”模式下打开了文件并写入了二进制数据(“r”是文本,“rb”是二进制)。虽然这在Linux中不会有任何影响,但当此代码在Windows上运行时可能会有所不同,供参考。 - mox1

6

试试这个,如果不是你想要的,请尝试解释它与你想要的有何区别。

void crea_fich(struct utilisateur *Tutilis)
{
   FILE *f;
   size_t nwritten;

   f = fopen("futilis.dat","wb");

   if (f == NULL)
   {
      fprintf(stderr, "Cannot open file for writing.\n");
      exit(1);
   }

   nwritten = fwrite(Tutilis, sizeof Tutilis[0], 1, f);
   fclose(f);

   if (nwritten < 1)
   {
      fprintf(stderr, "Writing to file failed.\n");
      exit(1);
   }
}

3
这个函数(同时使用fread()的相反函数)可以在任何一种机器结构上运行;然而,它不能在其他结构上移植。在这种情况下可能并不重要,但为了完整性起见还是值得提一下。 - Jonathan Leffler

6

迈克尔S是对的;使用fwrite与结构体一起使用非常不可移植。但是假设您不关心这一点,想要编写一些易于编写且有效的东西。

您代码中的问题在于,您已经破坏了sizeof的黄金法则:永远不要使用类型名称来使用sizeof。相反,您应该使用sizeof与一个左值,并且几乎总是使用另一个参数的解除引用。 因此:

Tutilis = malloc (sizeof (*Tutilis));
  ...
fwrite(Tutilis, sizeof (*Tutilis), 1, f);

如果你按照这个步骤去做,就不容易出现尺寸错误。

1
我很难把那称为"黄金法则"。今天大量的代码都调用sizeof而不是lvalue。微软自己的MSDN网站展示了如何在类型名称上调用它。http://msdn.microsoft.com/en-us/library/4s7x1k91.aspx - mox1
@James:这是完全合法的,只是不是一种非常健壮的编程实践。你不会因为MSDN告诉你如何跳崖而跳下去,对吧? :-) - Norman Ramsey

6
不行。您需要逐个编写数据成员。您不应该盲目地将结构体的内存表示复制到文件输出缓冲区中(显然,这正是您试图做的)。以这种方式编写文件会导致文件不可移植(除非它们在编写它们的平台上可读),因为结构元素的字节序和特定于平台的填充。

4
他从未说过需要可移植性,因此直接将struct写入文件系统的想法并没有明显错误。例如,我知道有一两个语言前端会对其解析树数据执行此操作。 - Mike Ellery
有一些适当的使用情况。我正在尝试写入IgorPxp文件。 - Script Kitty

1

我知道这是一个旧帖子,但当人们搜索这些信息时,它会出现,所以我将提供自己的解决方案。

这基本上是我在其中一个游戏中使用的。实际上,我在我的对话框函数中有一些额外的库特定代码,但本质上就是这样。我逐个编写数据。我不认为我有一个用于此数据的结构体,但没有区别,只需单独编写您的结构体成员即可。如前所述,这样做更好。

// returns 1 if successful, 0 if not
int savemap(const char *map_name)
{
   FILE *file = NULL;

   // open the file in write binary mode
   file = fopen(map_name, "wb");

   // always check return values to see if it was opened okay
   if(file == NULL) {
      fprintf(stderr, "Error opening file for writing.\n");
      return 0;
   }

   // write file ID, version and pills
   fwrite(MAP_ID, sizeof(char), strlen(MAP_ID)+1, file);
   fwrite(&MAP_VER, sizeof(unsigned char), 1, file);
   fwrite(&pills, sizeof(unsigned short), 1, file);

   // write the map data (unsigned int map[315])
   fwrite(&map, sizeof(unsigned int), 315, file);

   // never forget to close the file
   fclose(file);

   return 1;
}

0

我会先查看符号名称,例如NULLfprint,更不用说那个奇怪的\0了。另外,你应该在写入后关闭文件,以确保它被刷新到磁盘,并且要仔细检查futilis变量是否是包含有效可写路径的char*类型。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接