首页 > 代码库 > fread读取结构体注意事项

fread读取结构体注意事项

作者 : 卿笃军

函数原型

size_t fread ( void *buffer, size_t size, size_t count, FILE *stream) ;

参 数

buffer
用于接收数据的内存地址
size
要读写的字节数,单位是字节
count
要进行读写多少个size字节的数据项,每个元素是size字节.
stream
输入流

返回值

实际读取的元素个数.如果返回值与count不相同,则可能文件结尾或发生错误.
从ferror和feof获取错误信息或检测是否到达文件结尾.


C的文本读写和二进制读写:

 C的文本方读写与二进制读写的差别仅仅体现在回车换行符的处理上.文本方式写时,每遇到一个‘‘\n‘‘(0AH换行符),它将其换成‘‘\r \n‘‘(0D0AH,回车换行),然后再写入文件;当文本读取时,它每遇到一个‘‘\r\n‘‘将其反变化为‘‘\n‘‘,然后送到读缓冲区.二进制读写时,其不存在任何转换,直接将写缓冲区中数据写入文件.

参考文章:JianKun的博客,文本文件与二进制文件区别,http://www.cnblogs.com/zhangjiankun/archive/2011/11/27/2265184.html


那么,如果我们要用fread()来读取文本文件呢?下面我们来试一下:

新建一个.txt文件,命名为"f1.txt",然后在里面输入如下内容:


注意上图中的光标位置,我们在最后一行也添加了一个回车~~~

在面我们来看一下文件大小:48字节


咦,为什么会是48个字节呢?上面的文件中明明只有42个字符啊。这里就牵涉到windows记事本中的换行问题了:

"记事本中是用‘\r\n‘来实现换行的,并且在记事本中不显示出来"

哦!这下子明白了,原来我们敲了3个换行符。3*2 = 6 ,而6+42 = 48 刚刚好!!!

(当然,你也可以自己试一下,新建一个".txt"文件,在里面输入"123"然后保存,查看一下txt属性,这时候大小为3字节

然后你再打开txt在里面输入一个回车,保存,再查看一下属性,是不是变成5字节了?)


额,下面我们来实现以下读取文件,然后根据文件中的 第二列 中的字符串大小对 记事本中的行进行排序~~~

我们先构思一下要如何读取文件行,很简单,弄一个结构体:

typedef struct node 
{
	char a[4];
	char b[8];
	char c[4];
}LNode;


char a[4] :存放"123 "  (123后面还有一个空格也存放在a[]里面)

char b[8]  :存放"kbcdefg " (一直到20前面)

char c[4]  :存放"20\r\n"  (这里是要注意的) 

另外还牵涉到一个问题,就是非字符串如何比较大小?这里引入了strncmp()函数。


如果你 strcut _stat结构体看不懂的话,参见这里:C语言中如何获得文件大小,http://blog.csdn.net/qingdujun/article/details/25157107

 1 #include <stdio.h>
 2 #include <sys/types.h>
 3 #include <sys/stat.h>
 4 #include <malloc.h>
 5 #include <string.h>
 6 
 7 typedef struct node 
 8 {
 9     char a[4];
10     char b[8];
11     char c[4];
12 }LNode;
13 
14 int main()
15 {
16     FILE *fp1 = NULL, *fp2 = NULL;
17     struct _stat buf;
18     int i,j,n = 0;
19     LNode *fbuf = NULL, t;
20 
21     fp1 = fopen("f1.txt","rb");
22     fp2 = fopen("f2.txt","wb");
23 
24     _stat("f1.txt",&buf);                     //buf.st_size  文件大小
25     n = buf.st_size/(sizeof(LNode));          //获得文件行数
26 
27     fbuf = (LNode *)malloc(buf.st_size);
28 
29     for (i = 0; i < n; ++i)
30         fread(&fbuf[i],sizeof(LNode),1,fp1);  //读文件
31 
32     for (i = 1; i < n; ++i)
33         for (j = 0; j < n-i; ++j)             //按照b排序
34         {    
35             if (strncmp(fbuf[j].b,fbuf[j+1].b,7) < 0)
36             {
37                 t = fbuf[j];
38                 fbuf[j] = fbuf[j+1];
39                 fbuf[j+1] = t;
40             }
41         }
42     for (i = 0; i < n; ++i)                  //写文件
43         fwrite(&fbuf[i],sizeof(LNode),1,fp2);
44         
45     fclose(fp1);
46     fclose(fp2);
47 
48     return 0;
49 }

如下图,排好序的"f2.txt":



当然,上面的结构体里面定义的全部是char类型的成员,不涉及结构体的字节对齐问题。

如果牵涉到结构体的字节对齐问题,可能操作起来会更加复杂。

所以,如果不是必要,请不要用fread()函数读取文本文件。 fscanf(),fgets(),fgetc()等函数都能很好的读取文本文件。

如果你想了解结构体的字节对齐情况,你可以参见:结构体在内存中所占字节大小计算,http://blog.csdn.net/qingdujun/article/details/24844681

我的CSDN博客:http://blog.csdn.net/qingdujun/article/details/25299421