实验七

【实验结论】

Part1: 验证性实验

验证性实验1:已知文件file1.txt已经存在,将file1.txt中小写字母转换成大写后,另存为file2.txt。

运行结果:

更改文件路径,电脑的C盘下出现文件file3.txt。

fout = fopen("file2.txt", "w");
↓↓↓ 改为
fout = fopen("C:\\test\\file3.txt", "w");

 

注意:对于以"w"方式打开的文件,如果原先文件不存在,那么就新建一个;如果文件已经存在,那么,新写入的数据会覆盖文件中原来的内容。如果不想覆盖可以以"a"方式打开。

 

验证性实验2:已知文本数据文件file1.dat,从文件file1.dat中读入数据,找出最高分和最低分学生信息,并输出在屏幕上。

// 从文本文件file1.dat中读取数据,找出最高分和最低分学生信息,并输出在屏幕上
#include <stdio.h> 
#include <stdlib.h>

#define N 10

// 定义一个结构体类型STU 
typedef struct student {
    int num;
    char name[20];
    int score;
}STU;

int main() {
    STU st, stmax, stmin;
    int i;
    FILE *fp;
    
    // 以只读文本方式打开文件file1.dat 
    fp = fopen("file1.dat", "r");
    if( !fp ) {  // 如果打开失败,则输出错误提示信息,然后退出程序 
        printf("fail to open file1.dat\n");
        exit(0);
    }
    
    stmax.score = 0;    // 先假定最高分是0,后面如发现比当前最高分还高的分数,就更新最高分 
    stmin.score = 100;    // 先假定最低分是100分,后面如发现比当前最低分更低的分数,就更新最低分 
    
    while( !feof(fp) ) {
        fscanf(fp, "%d %s %d", &st.num, st.name, &st.score);  // 从fp指定的文件中格式化读取一个学生信息
        
        if(st.score > stmax.score)
            stmax = st;
        else if(st.score < stmin.score)
            stmin = st; 
    } 
    
    fclose(fp);
    
    printf("最高分学生信息: %5d%15s%5d\n", stmax.num, stmax.name, stmax.score);
    printf("最低分学生信息: %5d%15s%5d\n", stmin.num, stmin.name, stmin.score);

    return 0;
}

// 这是《C语言程序设计教程学习指导》「2.10 文件」中的实验,细微处做了微调
// 这个源代码没有考虑多个高分或多个低分的情形。

运行结果:

如果事先不知道学生人数,则程序应该如何修改?尝试对line29做如下修改:

for(i=0; i<N; i++)
↓↓↓ 改为
while( !feof(fp) )

再次运行时结果同上。

 

在事先不知道学生人数,且最高 / 最低分可能不止一个的情况下,对程序进行改写:

// 从文本文件file1.dat中读取数据,找出最高分和最低分学生信息,并输出在屏幕上
#include <stdio.h> 
#include <stdlib.h>

// 定义一个结构体类型STU 
typedef struct student {
    int num;
    char name[20];
    int score;
}STU;

int main() {
    STU st[20], stmax[5], stmin[5];
    int i=0,max,min,a,b=0,c=0;
    FILE *fp;
    
    // 以只读文本方式打开文件file1.dat 
    fp = fopen("file1.dat", "r");
    if( !fp ) {  // 如果打开失败,则输出错误提示信息,然后退出程序 
        printf("fail to open file1.dat\n");
        exit(0);
    }
    
    max = 0;    // 先假定最高分是0,后面如发现比当前最高分还高的分数,就更新最高分 
    min = 100;    // 先假定最低分是100分,后面如发现比当前最低分更低的分数,就更新最低分 
    
    while( !feof(fp) ) {
        fscanf(fp, "%d %s %d", &st[i].num, st[i].name, &st[i].score);  // 从fp指定的文件中格式化读取学生信息
        
        if(st[i].score > max)
            max = st[i].score;
        else if(st[i].score < min)
            min = st[i].score; 
            
            i++;
    } 
    a=i;
    for(i=0;i<a;i++){
        if(st[i].score == max)
        stmax[b++] = st[i];
        else if(st[i].score == min)
        stmin[c++] = st[i];
        
    }
    
    fclose(fp);
    
    printf("最高分学生信息:\n"); 
    for(i=0;i<b;i++)
    printf("%5d%15s%5d\n", stmax[i].num, stmax[i].name, stmax[i].score);
    printf("最低分学生信息:\n");
    for(i=0;i<c;i++)
    printf("%5d%15s%5d\n", stmin[i].num, stmin[i].name, stmin[i].score);

    return 0;
}

添加学生信息:

运行结果:

实现方式和之前做过的实验差不多,定义了结构体数组。

 

验证性实验3 & 验证性实验4

从文件file1.dat中读入数据,按成绩从高到低排序,将排序结果输出到屏幕上,同时也以文本 / 二进制方式存入文件file3.dat中。

运行结果:

屏幕上显示的内容相同。

文件中显示的内容不同,二进制文件中数据信息不直观可读。

二进制文件与文本文件的区别(来源于课件):

文本文件

数据以ASCⅡ码形式存储,也称ASCⅡ码文件 每个字节存放一个字符的ASCII码。

特点:存储量大、速度慢; 直观,便于对字符操作。

二进制文件

数据按其在内存中的存储形式原样存放。

特点:存储量小、速度快、便于存放中间结果;不直观。

 

写一个简单的程序,尝试从二进制文件file4.dat中读出数据,并在屏幕上显示,以此查看文件file4.dat的内容。

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

#define N 10

typedef struct student {
    int num;
    char name[20];
    int score;
}STU;

int main(){
    FILE *fp;
    int i;
    STU st[N];
    
    fp = fopen("file4.dat", "rb");
    if( !fp ) {
        printf("fail to open file4.dat\n");
        exit(0);
    }
    
    for(i=0; i<N; i++) 
        fread(&st[i],sizeof(STU),N,fp);
        
    for(i=0; i<N; i++)
        printf("%-6d%-10s%3d\n",st[i].num,st[i].name,st[i].score);
        
    fclose(fp);
    return 0;
}

运行结果:

注意:使用fprintf()和fscanf()写入和读出格式化数据时,用什么格式写入文件,就一定要以什么格式从文件读出,否则会造成数据出错。如果不需要转换数据的内外形式,可以直接使用块读写函数fwrite()和fread()进行写入和读出。

 

Part2: 编程练习

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
const int N = 10;

// 定义结构体类型struct student,并定义其别名为STU 
typedef struct student {
    long int id;
    char name[20];
    float objective;    /*客观题得分*/
    float subjective;    /*操作题得分*/
    float sum;
    char level[10];    
}STU; 

// 函数声明
void input(STU s[], int n);
void output(STU s[], int n);
void process(STU s[], int n);

int main() {
    STU stu[N];
    
    printf("录入%d个考生信息: 准考证号,姓名,客观题得分(<=40),操作题得分(<=60)\n", N); 
    input(stu, N);
    
    printf("\n对考生信息进行处理: 计算总分,确定等级\n");
    process(stu, N);
    
    printf("\n打印考生完整信息: 准考证号,姓名,客观题得分,操作题得分,总分,等级\n");
    output(stu, N); 
    
    return 0;
} 

// 从文本文件examinee.txt读入考生信息:准考证号,姓名,客观题得分,操作题得分
void input(STU s[], int n) {
    FILE *fp;
    int i;
    fp = fopen("examinee.txt","r");
    if(fp == NULL){
        printf("fail to open examinee.txt\n");
        exit(0);
    }
    for(i=0; i<N; i++)
        fscanf(fp,"%ld %s %f %f",&s[i].id,s[i].name,&s[i].objective,&s[i].subjective); 
        fclose(fp);
}

// 输出考生完整信息: 准考证号,姓名,客观题得分,操作题得分,总分,等级
// 不仅输出到屏幕上,还写到文本文件result.txt中 
void output(STU s[], int n) {
    FILE *fp;
    int i;
    fp = fopen("result.txt","w");
    if(fp == NULL){
        printf("fail to open result.txt\n");
        exit(0);
    }
    for(i=0; i<N; i++){
        printf("%ld %s %.2f %.2f %.2f %s\n",s[i].id,s[i].name,s[i].objective,s[i].subjective,s[i].sum,s[i].level);
        fprintf(fp,"%ld %s %.2f %.2f %.2f %s\n",s[i].id,s[i].name,s[i].objective,s[i].subjective,s[i].sum,s[i].level); 
    }
    fclose(fp);
}

// 对考生信息进行处理:计算总分,排序,确定等级
void process(STU s[], int n) {
    int i,j;
    STU temp;
    for(i=0;i<n;i++)
        s[i].sum=s[i].objective+s[i].subjective;
    
    
    for(i=0;i<n-1;i++){
        for(j=0;j<n-1-i;j++){
            if(s[j].sum<s[j+1].sum){
                temp=s[j];
                s[j]=s[j+1];
                s[j+1]=temp;
            }
        }
    }
    
    for(i=0;i<n;i++){
        if(i<n*0.1)
        strcpy(s[i].level,"优秀");
        else if(i>=n*0.1 && i<n*0.5)
        strcpy(s[i].level,"合格");
        else
        strcpy(s[i].level,"不合格");
    }    
    
}

运行结果:

 

Part3: 拓展综合应用

已知班级学生名单信息存在文本文件list.txt中,编程实现随机抽点5位学生信息,显示在屏幕上,同时,写入以系统日期命名的文件中。

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>

#define N 80

int main(){
    FILE *fin,*fout;
    int i,j,num[5];
    char str[N][64];
    time_t t;
    char strtime[60]={0};
    struct tm *info;
    
    t = time(0);
    info = localtime( &t );    //读取系统日期 
    strftime(strtime, 60, "%Y-%m-%d.txt", info);    //将系统日期转换为文件名形式的字符串    
    
    fin = fopen("list.txt","r");
    if(!fin){
        printf("fail to open list.txt");
        exit(0);
    }
    
    for(i=0; i<N; i++)
        fgets(str[i],64,fin);    //从文件中整行读取字符串 
    
    srand(time(0));    //使用系统时间的值作为随机种子 
    num[0] = rand() % N;     //取5个0 ~ N-1的随机数 
    for(i=1; i<5; i++){
        num[i] = rand() % N;
        for(j=0; j<i; j++){     //避免重复 
            if(num[i] == num[j]){
                num[i] = rand() % N;
                j = 0;
            }
        }
    }
    
    fout = fopen(strtime, "w");    //文件名是变量时,可以用地址(指针)传入 
    if(!fout){
        printf("fail to open %s",strtime);
        exit(0);
    }
    
    for(i=0; i<5; i++){
        printf("%s\n",str[num[i]]);
        fprintf(fout,"%s\n",str[num[i]]);
    }
    
    fclose(fin);
    fclose(fout);
    return 0;
    
}

运行结果:

总结:

1.用rand()%N生成一个小于N的随机数的操作是在百科园第八章看到的,感觉还挺好用的。一开始用rand()函数的时候没有写srand(time(0)),导致每次运行时结果没有变化,查阅之后才知道可以使用系统时间作为随机种子。

2为了弄清localtime()和strftime()函数的使用方法查看了不少网站,大致明白了调用的格式,细节方面还没太搞懂。

3.fopen()函数中如何用变量做文件名也是我困惑好久的地方,看到了几种方法还是把".txt"直接放在strftime()函数里比较方便,但这里我有个小疑问,我原来这一行写的是:

strftime(strtime, 60, "%Y-%m-%d %H:%M:%S.txt", info);
                 ↓↓↓ 改为
strftime(strtime, 60, "%Y-%m-%d.txt", info); 

但这个时候运行显示文件无法正常打开,我找了好久的问题最后把后面部分删掉就正常了。这里出现问题的原因是什么呢?

4.写避免重复点名的时候忘了用标识法,就写成了循环,后来看了同学的才发现用标识更为简洁一些。

5.可能程序中还有些小错误,欢迎指出。

 

【实验总结与体会】

1.这次实验学习了有关文件的内容。当需要输入和输出大量数据时,文件可以替代键盘的输入,还能够进行数据的保存,起到相当重要的作用。

2.关于文件的函数的调用方法和注意事项在前面也写到了一些,还是要通过多运用来熟悉它们。通过文件指针来操作文件的方法虽然没有在实验里用到,如果能够掌握的话应该会对编程更有帮助。

3.想到这是最后一次实验,就尽力地来完成了,虽然因此花费了好多时间,但还是值得的。

4.希望大家期末都能取得好成绩!

 

posted @ 2019-06-19 20:23  PKD  阅读(263)  评论(4编辑  收藏  举报