【实验结论】


Part1: 验证性实验 

• 验证性实验二

将line29的代码做修改后的程序源码:

 1 // 从文本文件file1.dat中读取数据,找出最高分和最低分学生信息,并输出在屏幕上
 2 #include <stdio.h> 
 3 #include <stdlib.h>
 4 
 5 #define N 10
 6 
 7 // 定义一个结构体类型STU 
 8 typedef struct student {
 9     int num;
10     char name[20];
11     int score;
12 }STU;
13 
14 int main() {
15     STU st, stmax, stmin;
16     int i;
17     FILE *fp;
18     
19     // 以只读文本方式打开文件file1.dat 
20     fp = fopen("file1.dat", "r");
21     if( !fp ) {  // 如果打开失败,则输出错误提示信息,然后退出程序 
22         printf("fail to open file1.dat\n");
23         exit(0);
24     }
25     
26     stmax.score = 0;    // 先假定最高分是0,后面如发现比当前最高分还高的分数,就更新最高分 
27     stmin.score = 100;    // 先假定最低分是100分,后面如发现比当前最低分更低的分数,就更新最低分 
28     
29     while(!feof(fp)){
30         fscanf(fp, "%d %s %d", &st.num, st.name, &st.score);  // 从fp指定的文件中格式化读取一个学生信息
31         
32         if(st.score > stmax.score)
33             stmax = st;
34         else if(st.score < stmin.score)
35             stmin = st; 
36     } 
37     
38     fclose(fp);
39     
40     printf("最高分学生信息: %5d%15s%5d\n", stmax.num, stmax.name, stmax.score);
41     printf("最低分学生信息: %5d%15s%5d\n", stmin.num, stmin.name, stmin.score);
42 
43     return 0;
44 }
验证性实验二

运行结果截图:

                                                             

                                  

 由运行结果可知,在不知道总人数的情况下,将line29的代码改为  while( !feof(fp) )  之后,运行结果仍然是正确的。

这是因为,函数feof()是用于判断文件是否到了结束标志,函数的返回值若是非0的数,则说明文件指针已指向文件的结尾了。在这段代码中结构体变量st会一直从文件中读取数据,直到文件中的数据都已被访问。

• 对比验证性实验3和验证性实验4的程序源码及运行结果,总结比较二进制文件与文本文件的区别

▶ 验证性实验3:

程序源码:

 1 // 从文本数据文件file1.dat中读入数据,按成绩从高到低排序,将排序结果输出到屏幕上,同时以文本方式存入文件file3.dat中。
 2 #include <stdio.h> 
 3 #include <stdlib.h>
 4 
 5 #define N 10
 6 
 7 // 定义一个结构体类型STU 
 8 typedef struct student {
 9     int num;
10     char name[20];
11     int score;
12 }STU;
13 
14 void sort(STU *pst, int n);  // 函数声明 
15 
16 int main() {
17     FILE *fin, *fout;
18     STU st[N];
19     int i;
20     
21     // 以只读文本方式打开文件file1.dat 
22     fin = fopen("file1.dat", "r");
23     if( !fin ) {  // 如果打开失败,则输出错误提示信息,然后退出程序 
24         printf("fail to open file1.dat\n");
25         exit(0);
26     }
27     
28     // 从fin指向的数据文件file1.dat中读取数据到结构体数组st
29     for(i=0; i<N; i++) 
30         fscanf(fin, "%d %s %d", &st[i].num, st[i].name, &st[i].score);
31     
32     fclose(fin);  // 关闭fin指向的文件file1.dat
33     
34     // 调用函数sort()对数组st中数据,按分数又高到低排序 
35     sort(st, N);
36     
37     // 以写方式打开/创建文本文件file3.dat
38     fout = fopen("file3.dat", "w");
39     if( !fout ) {  // 如果打开失败,则输出错误提示信息,然后退出程序 
40         printf("fail to open file1.dat\n");
41         exit(0);
42     }
43     
44     // 将排序后的数组st中数据输出到屏幕,同时,也写入文件file3.dat
45     for(i=0; i<N; i++) {
46         printf("%-6d%-10s%3d\n", st[i].num, st[i].name, st[i].score);
47         fprintf(fout, "%-6d%-10s%3d\n", st[i].num, st[i].name, st[i].score);
48     }
49         
50     fclose(fout);  // 关闭fout指向的文件file3.dat
51     
52     return 0;
53 }
验证性实验3

运行结果截图:

                    

 ▶ 验证性实验4:

 程序源码:

 1 // 从文本数据文件file1.dat中读入数据,按成绩从高到低排序,并将排序结果输出到屏幕上,同时,也以二进制方式存入文件file4.dat中。
 2 #include <stdio.h> 
 3 #include <stdlib.h>
 4 
 5 #define N 10
 6 
 7 // 定义一个结构体类型STU 
 8 typedef struct student {
 9     int num;
10     char name[20];
11     int score;
12 }STU;
13 
14 void sort(STU *pst, int n);  // 函数声明 
15 
16 int main() {
17     FILE *fin, *fout;
18     STU st[N];
19     int i;
20     
21     // 以只读文本方式打开文件file1.dat 
22     fin = fopen("file1.dat", "r");
23     if( !fin ) {  // 如果打开失败,则输出错误提示信息,然后退出程序 
24         printf("fail to open file1.dat\n");
25         exit(0);
26     }
27     
28     // 从fin指向的数据文件file1.dat中读取数据到结构体数组st
29     for(i=0; i<N; i++) 
30         fscanf(fin, "%d %s %d", &st[i].num, st[i].name, &st[i].score);
31     
32     fclose(fin);  // 关闭fin指向的文件file1.dat
33     
34     // 调用函数sort()对数组st中数据,按分数由高到低排序 
35     sort(st, N);
36     
37     // 以写方式打开/创建二进制文件file4.dat
38     fout = fopen("file4.dat", "wb");
39     if( !fout ) {  // 如果打开失败,则输出错误提示信息,然后退出程序 
40         printf("fail to open file1.dat\n");
41         exit(0);
42     }
43     
44     // 将排序后的数组st中数据输出到屏幕
45     for(i=0; i<N; i++) 
46         printf("%-6d%-10s%3d\n", st[i].num, st[i].name, st[i].score);
47     
48     // 将排序后的数组st中数据写到二进制文件file4.dat
49     fwrite(st, sizeof(STU), N, fout);  // 将从地址st开始的sizeof(STU)×N个字节信息写入fout指向的文件file4.dat中 
50         
51     fclose(fout);  // 关闭fout指向的文件file4.dat
52     
53     return 0;
54 }
55 
56 
57 // 函数功能描述:对pst指向的n个STU结构体数据进行排序,按成绩数据项由高到底排序 
58 // 排序算法:冒泡法 
59 void sort(STU *pst, int n) {
60     STU *pi, *pj, t;
61     
62     for(pi = pst; pi < pst+n-1; pi++)
63         for(pj = pi+1; pj < pst+n; pj++) 
64             if(pi->score < pj->score) {
65                 t = *pi;
66                 *pi = *pj;
67                 *pj = t; 
68             }
69     
70     
71 } 
验证性实验4

运行结果截图:

                    

二进制文件与文本文件的区别总结:

 

 

数据类型

数据长度

读取软件

操作系统对换行符'\n‘’的处理

文本文件

只能以字符形式储存变量。

固定长度。如ASCII码每条数据(每个字符)都是1个字节

文本文件编辑器

操作系统会对'\n'进行一些隐式变换

二进制文件

可以存储char/int/short/long/float/等各种变量值。

不固定。如short占两个字节,int占四个字节,float占8个字节。

不同类型的需要特别解码器。

操作系统不会对'\n'进行隐式变换。

二进制文件file4.dat中读出数据:

程序源码: 

 1 #include<stdio.h>
 2 #include<stdlib.h>
 3 typedef struct student {
 4 int  num;
 5 char name[20];
 6 int  score;
 7 }STU;
 8 int main()
 9 {
10     FILE *fp;
11     STU st[10];
12     int i=0,j;
13     if((fp=fopen("file4.dat","rb"))==NULL)
14     {
15         printf("Failed to open file");
16         exit(0);
17     }
18     while(!feof(fp))
19     {
20         if(fread(&st[i],sizeof(struct student),1,fp) == 1) {
21             printf("%-6d %-10s %3d\n", st[i].num, st[i].name, st[i].score);
22             i++;
23         }
24     }
25     
26     fclose(fp);
27     return 0;
28 }
ex1_4_1

运行结果截图:

 

这里运行结果的最后一行有什么意义?求解答!

↑这里根据老师的建议已经修改了代码,完美运行!( ̄▽ ̄)/    顺便做个对比吧。

修改前while语句内的代码:

1 fread(&st[i],sizeof(struct student),1,fp);  
2 printf("%-6d %-10s %3d\n", st[i].num, st[i].name, st[i].score); 
3 i++;

运行结果截图:

Part2: 编程练习

程序源码:

 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <stdlib.h>
 4 const int N = 10;
 5 
 6 // 定义结构体类型struct student,并定义其别名为STU 
 7 typedef struct student {
 8     long int id;
 9     char name[20];
10     float objective;    /*客观题得分*/
11     float subjective;    /*操作题得分*/
12     float sum;
13     char level[10];    
14 }STU; 
15 
16 // 函数声明
17 void input(STU s[], int n);
18 void output(STU s[], int n);
19 void process(STU s[], int n);
20  
21 int main() {
22     STU stu[N];
23     
24     printf("录入%d个考生信息: 准考证号,姓名,客观题得分(<=40),操作题得分(<=60)\n", N); 
25     input(stu, N);
26      
27     printf("\n对考生信息进行处理: 计算总分,确定等级\n");
28     process(stu, N);
29     
30     printf("\n打印考生完整信息: 准考证号,姓名,客观题得分,操作题得分,总分,等级\n");
31     output(stu, N); 
32     
33     return 0;
34 } 
35 
36 // 录入考生信息:准考证号,姓名,客观题得分,操作题得分
37 void input(STU s[], int n) {
38     FILE *fin;
39     // 以只读文本方式打开文件examinee.txt
40     fin=fopen("examinee.txt","r");
41     if( !fin ) {  // 如果打开失败,则输出错误提示信息,然后退出程序 
42         printf("Failed to open file\n");
43         exit(0);
44     }
45     int i;
46     for(i=0;i<n;i++)
47     {
48         // 从fin指定的文件中格式化读取学生信息
49         if(fscanf(fin,"%ld %s %f %f",&s[i].id,s[i].name,&s[i].objective,&s[i].subjective)==0)
50              printf("读取错误!"); 
51     }
52     fclose(fin);
53 }
54 
55 //输出考生完整信息: 准考证号,姓名,客观题得分,操作题得分,总分,等级
56 void output(STU s[], int n) {
57      int i;
58      FILE *fout;
59      // 以只写文本方式打开/创建文件result.txt
60      fout=fopen("result.txt","w");
61      //在屏幕和文档中打印表头 
62      printf("准考证号   姓名   客观题得分   操作题得分   总分   等级\n");
63      fprintf(fout,"准考证号   姓名   客观题得分   操作题得分   总分   等级\n");
64      for(i=0;i<n;i++)// 格式化输出学生信息到fout指定的文件中
65      {
66          printf("  %-9ld%-10s%-13.2f%-10.2f%-7.2f%-8s\n",
67             s[i].id,s[i].name,s[i].objective,s[i].subjective,s[i].sum,s[i].level);
68         fprintf(fout,"  %-9ld  %-10s%-13.2f%-10.2f%-7.2f%-8s\n",
69             s[i].id,s[i].name,s[i].objective,s[i].subjective,s[i].sum,s[i].level); 
70      }
71      fclose(fout);      
72 }
73 
74 // 对考生信息进行处理:计算总分,排序,确定等级
75 void process(STU s[], int n) {
76     int i,j,k;
77     int a1,a2;                  //用来表示10%和50%两个分界点 
78     a1=(int)(N*0.1),a2=(int)(N*0.5);
79     STU temp;
80     for(i=0;i<n;i++)
81     s[i].sum=s[i].objective+s[i].subjective;
82     for(j=0;j<n-1;j++)
83        for(k=0;k<n-j-1;k++)
84           if(s[k].sum<s[k+1].sum)
85           {
86               temp=s[k];
87               s[k]=s[k+1];
88               s[k+1]=temp;
89           }
90     for(i=0;i<a1;i++)
91     strcpy(s[i].level,"优秀");
92     for(i=a1;i<a2;i++)
93     strcpy(s[i].level,"合格");
94     for(i=a2;i<n;i++)
95     strcpy(s[i].level,"不合格");
96 }
97  
编程练习

运行结果截图:

Part3: 拓展综合应用

程序源码:

 1 #include<stdio.h>
 2 #include<time.h>
 3 #include<stdlib.h>
 4 #include<string.h>
 5 #define N 80
 6 typedef struct{
 7   int  number;
 8   char stu_number[10];
 9   char name[10];
10   char class_name[20];
11   int flag;             //用于标志是否已被抽取到,防止重复抽取相同数据 
12 }STU; 
13 int main(){
14     FILE *fin,*fout;
15     int i,j;
16     STU list[N];
17     
18     //数据读入 
19     fin=fopen("list.txt","r");    
20     if(!fin){
21         printf("Failed to open file");
22         exit(0);
23     }
24     for(i=0;i<N;i++){
25         fscanf(fin,"%d %s %s %s", &list[i].number,
26                                   list[i].stu_number,
27                                   list[i].name,
28                                   list[i].class_name);
29         list[i].flag=0;                          
30     }
31     fclose(fin);
32     
33     //确定导出文件名 
34     char buff[20];         
35     struct tm *t;
36     time_t tt;
37     time(&tt);
38     //调用 localtime函数查阅系统日期 
39     t=localtime(&tt);
40     //调用 strftime函数将时间日期转换为字符串 
41     if (!strftime(buff, sizeof buff, "%Y-%m-%d",t)) 
42         //"%Y-%m-%d"这里有很多C99标准的代码无法使用 
43         puts("strftime failed");
44     strcat(buff,".txt");  //字符串连接函数--在字数串数组的结尾加上文件扩展名 
45     
46     //数据抽取、导出
47     srand(time(NULL));               
48     fout=fopen(buff,"w");
49     if(!fout){
50         printf("Failed to open file");
51         exit(0);
52     }
53     i=0;
54     printf("Five lucky people:\n");
55     while(i++<5){
56        //生成随机数 
57        j=rand()%N;
58        if(list[j].flag==0){
59            fprintf(fout,"%02d %10s %-8s %-20s\n",list[j].number,
60                                               list[j].stu_number,
61                                               list[j].name,
62                                               list[j].class_name);
63         printf("%-2d %10s %-8s %-20s\n", list[j].number,
64                                          list[j].stu_number,
65                                          list[j].name,
66                                          list[j].class_name);
67         list[j].flag=1;    //对已经抽到的成员进行标识                                         
68        }
69        else{
70               i--;
71               continue;
72        }                  
73     }
74     fclose(fout);
75     return 0;    
76 }
综合应用

运行结果截图:

【实验总结与体会】


 从文件读取数据的价值在程序需要大容量数据输入时体现得尤为突出,正好解决了在实验六中在调试程序时需要反复输入多组数据的烦恼。

实验中踩的坑:     (1)在进行二进制读写操作时,一定要使用fread(),fwrite()函数而不能使用fscanf(),fprintf()函数,否则会出现乱码或达不到预期的效果;

                         (2)在学习调用localtime()和strftime()函数时花了不少时间,也失败了很多次,尽管最后成功了还是有一些细节没有完全弄懂,还是需要多查资料看别人写的规范的代码;

                         (3)从二进制文件读取代码时末尾出现的乱码不知道是哪里出了问题。 

 

评论博客地址 


 

 https://www.cnblogs.com/1256096713a/

 https://www.cnblogs.com/awjwj/

 https://www.cnblogs.com/431-w-34-m-q