C语言程序设计(十三) 文件操作

第十三章 文件操作

  • 文本文件:将数值型数据的每一位数字作为一个字符以其ASCII码的形式存储(每一位数字都单独占用一个字节的存储空间)
  • 二进制文件:数据值是以二进制形式存储的

文本文件可以方便地被其他程序读取,且其输出与字符一一对应,便于对字符进行逐个处理和输出,但一般占用的存储空间较大,且需花费ASCII码和字符间的转换时间

  • 字节流:C语言把数据看成是由字节构成的序列
  • 流式文件:输入/输出的数据仅受程序的控制而不受物理符号的控制

缓冲型和非缓冲型文件系统

fopen:

FILE *fopen(const char *filename, const chat *mode);
r 只读
w 只写(覆盖)
a 只写(添加)
+ 读写
b 二进制

fclose:

在文件使用结束后必须关闭文件

int fclose(FILE *fp);

关闭成功,返回0值,否则返回一个非0值

读写文件中的字符:

int fgetc(FILE *fp);

从fp所指的文件中读取一个字符,并将位置指针指向下一个字符,读取成功,返回该字符,读到文件末尾,返回EOF = -1

int fputc(int c, FILE *fp);

将字符c写到文件指针fp所指的文件中,写入错误,返回EOF,否则返回字符c

//L13-1

#include <stdio.h>
#include <stdlib.h>
int main()
{
    FILE *fp;
    char ch;
    if ((fp = fopen("C:\\Users\\lenovo\\Desktop\\demo.txt","w")) == NULL) /* 判断文件是否成功打开 */
    { 
        printf("Failure to open demo.txt!\n");
        exit(0);
    }
    ch = getchar();
    while (ch != '\n')   /* 若键入回车换行符则结束键盘输入和文件写入 */              
    {   
        fputc(ch, fp);
        ch = getchar();  
    }
    fclose(fp);           /* 关闭由函数fopen()打开的文件demo.txt */
    return 0;
}

//L13-2

#include <stdio.h>
#include <stdlib.h>
int main()
{
    FILE *fp;
    char ch;
    int i;
    if ((fp = fopen("C:\\Users\\lenovo\\Desktop\\demo.bin","wb")) == NULL) /* 以二进制写方式打开文件 */
    { 
        printf("Failure to open demo.bin!\n");
        exit(0);
    }
    for (i=0; i<128; i++)
    {      
        fputc(i, fp);     /* 将ASCII码值在0-127之间的所有字符写入文件 */
    }
    fclose(fp);
    if ((fp = fopen("C:\\Users\\lenovo\\Desktop\\demo.bin","rb")) == NULL) /* 以二进制读方式打开文件 */
    { 
        printf("Failure to open demo.bin!\n");
        exit(0);
    }
    while ((ch = fgetc(fp)) != EOF)     /* 从文件中读取字符直到文件末尾 */    
    {
        putchar(ch);         /* 在显示器上显示从文件读出的所有字符 */ 
    }
    fclose(fp);
    return 0;
}
//运行结果
 
 !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~

//L13-3

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
int main()
{
    FILE *fp;
    char ch;
    int i;
    if ((fp = fopen("demo.bin","wb")) == NULL) /* 以二进制写方式打开文件 */
    { 
        printf("Failure to open demo.bin!\n");
        exit(0);
    }
    for (i=0; i<128; i++)
    {      
        fputc(i, fp);     /* 将字符的ASCII码值写入文件 */
    }
    fclose(fp);
    if ((fp = fopen("demo.bin","rb")) == NULL) /* 以二进制读方式打开文件 */
    { 
        printf("Failure to open demo.bin!\n");
        exit(0);
    }
    while ((ch = fgetc(fp)) != EOF)     /* 从文件中读取字符直到文件末尾 */
    {
        if (isprint(ch))         /* 判断是否是可打印字符 */
        {
            printf("%c\t", ch); /* 若是可打印字符,则显示该字符 */
        }
        else
        {
            printf("%d\t", ch); /*若非可打印字符,则显示该字符的ASCII码值*/
        }
    }
    fclose(fp);
    return 0;
}
//运行结果
0       1       2       3       4       5       6       7       8       9       10      11      12      13      14
15      16      17      18      19      20      21      22      23      24      25      26      27      28      29
30      31              !       "       #       $       %       &       '       (       )       *       +       ,
-       .       /       0       1       2       3       4       5       6       7       8       9       :       ;
<       =       >       ?       @       A       B       C       D       E       F       G       H       I       J
K       L       M       N       O       P       Q       R       S       T       U       V       W       X       Y
Z       [       \       ]       ^       _       `       a       b       c       d       e       f       g       h
i       j       k       l       m       n       o       p       q       r       s       t       u       v       w
x       y       z       {       |       }       ~       127

feof()用于检查是否到达文件末尾,当文件位置指针指向文件结束符时,返回非0值,否则返回0值

ferror()用于检查是否出现文件错误,如果出现错误返回非0值,否则返回0值

fgets()读写文件中的字符串

char *fgets(char *s, int n, FILE *fp)

函数从fp所指的文件中读取字符串并在字符串末尾添加'\0',然后存入s,最多读取n-1个字符

当读到回车换行符、到达文件尾或读满n-1个字符时,函数返回该字符串的首地址,即指针s的值,读取失败则返回空指针

//L13-4

#include <stdio.h>
#include <stdlib.h>
#define N 80
int main()
{
    FILE *fp;
    char str[N];
    if ((fp = fopen("C:\\Users\\lenovo\\Desktop\\demo.txt","a")) == NULL) /* 以添加方式打开文本文件 */
    { 
        printf("Failure to open demo.txt!\n");
        exit(0);
    }
    gets(str);              /* 从键盘读入一个字符串 */
    fputs(str, fp);        /* 将字符串str写入fp所指的文件 */
    fclose(fp);
    if ((fp = fopen("C:\\Users\\lenovo\\Desktop\\demo.txt","r")) == NULL) /* 以读方式打开文本文件 */
    { 
        printf("Failure to open demo.txt!\n");
        exit(0);
    }
    fgets(str, N, fp);   /* 从fp所指的文件中读出字符串,最多读N-1个字符 */
    puts(str);             /* 将字符串送到屏幕显示 */
    fclose(fp);
    return 0;
}
//运行结果
I am happy.
I am a student.I am happy.

与gets()不同的是,fgets()从指定的流读字符串,读到换行符时将换行符也作为字符串的一部分读到字符串中来

同理,与puts()不同的是,fputs()不会在写入文件的字符串末尾加上换行符

按格式读写文件:

int fscanf(FILE *fp, const char *format, ...);
int fprint(FILE *fp, const char *format, ...);

//L13-5

#include  <stdio.h>
#include  <stdlib.h>
#define N 30
typedef struct date
{
    int   year;
    int   month;
    int   day;
}DATE;
typedef struct student
{
    long  studentID;            /* 学号 */
    char  studentName[10];         /* 姓名 */
    char  studentSex;            /* 性别 */
    DATE  birthday;                 /* 出生日期 */
    int      score[4];                 /* 4门课程的成绩 */
    float aver;                   /* 平均分 */
}STUDENT;
void InputScore(STUDENT stu[], int n, int m);
void AverScore(STUDENT stu[], int n, int m);
void WritetoFile(STUDENT stu[], int n, int m);
int main()
{
    STUDENT stu[N];
    int n;
    printf("How many student?");
    scanf("%d", &n);
    InputScore(stu, n, 4);
    AverScore(stu, n, 4);
    WritetoFile(stu, n, 4);
    return 0;
}
/*从键盘输入n个学生的学号、姓名、性别、出生日期以及m门课程的成绩到结构体数组stu中*/
void InputScore(STUDENT stu[], int n, int m)
{
    int i, j;
    for (i=0; i<n; i++)
    {
        printf("Input record %d:\n", i+1);
        scanf("%ld", &stu[i].studentID);
        scanf("%s", stu[i].studentName);
        scanf(" %c", &stu[i].studentSex); /* %c前有一个空格 */
        scanf("%d", &stu[i].birthday.year);
        scanf("%d", &stu[i].birthday.month);
        scanf("%d", &stu[i].birthday.day);
        for (j=0; j<m; j++)
        {
            scanf("%d", &stu[i].score[j]);
        }
    }
}
/* 计算n个学生的m门课程的平均分,存入数组aver中 */
void AverScore(STUDENT stu[], int n, int m)
{
    int i, j, sum;
    for (i=0; i<n; i++)
    {
        sum = 0;
        for (j=0; j<m; j++)
        {
            sum = sum + stu[i].score[j];
        }
        stu[i].aver = (float)sum/m;
    }
}
/* 输出n个学生的学号、姓名、性别、出生日期以及m门课程的成绩到文件score.txt中 */
void WritetoFile(STUDENT stu[], int n, int m)
{
    FILE *fp;
    int i, j;
    if ((fp = fopen("C:\\Users\\lenovo\\Desktop\\score.txt","w")) == NULL) /* 以写方式打开文本文件 */
    {
        printf("Failure to open score.txt!\n");
        exit(0);
    }
     fprintf(fp, "%d\t%d\n", n, m);    /*将学生人数和课程门数写入文件*/
    for (i=0; i<n; i++)
    {
        fprintf(fp, "%10ld%8s%3c%6d/%02d/%02d",  stu[i].studentID,
stu[i].studentName,
stu[i].studentSex,
stu[i].birthday.year,
stu[i].birthday.month,
stu[i].birthday.day);
        for (j=0; j<m; j++)
        {
            fprintf(fp, "%4d", stu[i].score[j]);
        }
        fprintf(fp, "%6.1f\n", stu[i].aver);
    }
    fclose(fp);
}

//L13-6

#include  <stdio.h>
#include  <stdlib.h>
#define N 30
typedef struct date
{
    int   year;
    int   month;
    int   day;
}DATE;
typedef struct student
{
    long  studentID;            /* 学号 */
    char  studentName[10];         /* 姓名 */
    char  studentSex;            /* 性别 */
    DATE  birthday;                 /* 出生日期 */
    int      score[4];                 /* 4门课程的成绩 */
    float aver;                   /* 平均分 */
}STUDENT;
void ReadfromFile(STUDENT stu[], int *n, int *m);
void PrintScore(STUDENT stu[], int n, int m);
int main()
{
    STUDENT stu[N];
    int n,  m = 4;
    ReadfromFile(stu, &n, &m);
    PrintScore(stu, n, m);
    return 0;
}
/*从文件中读取学生的学号、姓名、性别、出生日期及成绩到结构体数组stu中*/
void ReadfromFile(STUDENT stu[], int *n, int *m)
{
    FILE *fp;
    int i, j;
    if ((fp = fopen("score.txt","r")) == NULL) /* 以读方式打开文本文件 */
    {
        printf("Failure to open score.txt!\n");
        exit(0);
    }
    fscanf(fp, "%d\t%d", n, m); /* 从文件中读出学生人数和课程门数 */
    for (i=0; i<*n; i++)    /*学生人数保存在n指向的存储单元*/
    {
        fscanf(fp, "%10ld", &stu[i].studentID);
        fscanf(fp, "%8s", stu[i].studentName);
        fscanf(fp, " %c", &stu[i].studentSex); /* %c前有一个空格 */
        fscanf(fp, "%6d/%2d/%2d", &stu[i].birthday.year,
&stu[i].birthday.month,
&stu[i].birthday.day);
        for (j=0; j<*m; j++) /*课程门数保存在m指向的存储单元*/
        {
            fscanf(fp, "%4d", &stu[i].score[j]);
        }
        fscanf(fp, "%f", &stu[i].aver);      /* 不能使用%6.1f格式 */
    }
    fclose(fp);

}
/* 输出n个学生的学号、姓名、性别、出生日期、m门课程的成绩及平均分到屏幕上 */
void PrintScore(STUDENT stu[], int n, int m)
{
    int i, j;
    for (i=0; i<n; i++)
    {
        printf("%10ld%8s%3c%6d/%02d/%02d",
        stu[i].studentID, stu[i].studentName, stu[i].studentSex,
        stu[i].birthday.year, stu[i].birthday.month, stu[i].birthday.day);
        for (j=0; j<m; j++)
        {
            printf("%4d", stu[i].score[j]);
        }
        printf("%6.1f\n", stu[i].aver);
    }
}

按数据块读写文件:

unsigned int fread(void *buffer, unsigned int size, unsigned int conut, FILE *fp);

从fp所指的文件中读取数据块并存储到buffer指向的内存中

buffer是待读入数据的起始地址,size是每个数据块的大小,count是允许读取的数据块

函数返回的是实际读到的数据块个数

unsigned int fwrite(const void *buffer, unsigned int size, unsigned int conut, FILE *fp);

//L13-7

#include  <stdio.h>
#include  <stdlib.h>
#define N 30
typedef struct date
{
    int   year;
    int   month;
    int   day;
}DATE;
typedef struct student
{
    long  studentID;            /* 学号 */
    char  studentName[10];         /* 姓名 */
    char  studentSex;            /* 性别 */
    DATE  birthday;                 /* 出生日期 */
    int      score[4];                 /* 4门课程的成绩 */
    float aver;                   /* 4门课程的 平均分 */
}STUDENT;
void InputScore(STUDENT stu[], int n, int m);
void AverScore(STUDENT stu[], int n, int m);
void WritetoFile(STUDENT stu[], int n);
int  ReadfromFile(STUDENT stu[]);
void PrintScore(STUDENT stu[], int n, int m);
int main()
{
    STUDENT stu[N];
    int n, m = 4;
    printf("How many student?");
    scanf("%d", &n);
    InputScore(stu, n, m);
    AverScore(stu, n, m);
    WritetoFile(stu, n);
    n = ReadfromFile(stu);
    PrintScore(stu, n, m);
    return 0;
}
/*从键盘输入n个学生的学号、姓名、性别、出生日期以及m门课程的成绩到结构体数组stu中*/
void InputScore(STUDENT stu[], int n, int m)
{
    int i, j;
    for (i=0; i<n; i++)
    {
        printf("Input record %d:\n", i+1);
        scanf("%ld", &stu[i].studentID);
        scanf("%s", stu[i].studentName);
        scanf(" %c", &stu[i].studentSex); /* %c前有一个空格 */
        scanf("%d", &stu[i].birthday.year);
        scanf("%d", &stu[i].birthday.month);
        scanf("%d", &stu[i].birthday.day);
        for (j=0; j<m; j++)
        {
            scanf("%d", &stu[i].score[j]);
        }
    }
}
/* 计算n个学生的m门课程的平均分,存入数组aver中 */
void AverScore(STUDENT stu[], int n, int m)
{
    int i, j, sum[N];
    for (i=0; i<n; i++)
    {
        sum[i] = 0;
        for (j=0; j<m; j++)
        {
            sum[i] = sum[i] + stu[i].score[j];
        }
        stu[i].aver = (float)sum[i]/m;
    }
}
/* 输出n个学生的学号、姓名、性别、出生日期以及m门课程的成绩到文件student.txt中 */
void WritetoFile(STUDENT stu[], int n)
{
    FILE *fp;
    if ((fp = fopen("student.txt","w")) == NULL) /* 以写方式打开文本文件 */
    {
        printf("Failure to open student.txt!\n");
        exit(0);
    }
    fwrite(stu, sizeof(STUDENT), n, fp);           /* 按数据块写文件 */
    fclose(fp);
}
/*从文件中读取学生的学号、姓名、性别、出生日期及成绩到结构体数组stu中并返回学生数*/
int ReadfromFile(STUDENT stu[])
{
    FILE *fp;
    int i;
    if ((fp = fopen("student.txt","r")) == NULL) /* 以读方式打开文本文件 */
    {
        printf("Failure to open student.txt!\n");
        exit(0);
    }
    for (i=0; !feof(fp); i++)
    {
        fread(&stu[i], sizeof(STUDENT), 1, fp); /* 按数据块读文件 */
    }
    fclose(fp);
    printf("Total students is %d.\n", i-1); /* 返回文件中的学生记录数 */
    return i-1; /* 返回文件中的学生记录数 */
}
/* 输出n个学生的学号、姓名、性别、出生日期、m门课程的成绩及平均分到屏幕上 */
void PrintScore(STUDENT stu[], int n, int m)
{
    int i, j;
    for (i=0; i<n; i++)
    {
        printf("%10ld%8s%3c%6d/%02d/%02d",
        stu[i].studentID, stu[i].studentName, stu[i].studentSex,
        stu[i].birthday.year, stu[i].birthday.month, stu[i].birthday.day);
        for (j=0; j<m; j++)
        {
            printf("%4d", stu[i].score[j]);
        }
        printf("%6.1f\n", stu[i].aver);
    }
}

文件的随机读写:

不同于顺序读写的是,文件的随机访问允许在文件位置中随机定位,并在文件的任何位置直接读写数据

为了实现文件的定位,在每一个打开的文件中都有一个文件位置指针,也称为文件位置标记,用来指向当前读写文件的位置,它保存了文件中的位置信息

当需要随机读写文件数据时,需要强制移动文件位置指针指向特定的位置

int fseek(FILE *fp, long offset, int fromwhere);

将fp的文件位置指针,从fromwhere开始移动offset个字节,表示下一个要读取的数据的位置

  • fromwhere为SEEK_SET或0,代表文件开始处
  • fromwhere为SEEK_CUR或1,代表文件当前位置
  • fromwhere为SEEK_END或2,代表文件结尾处

void rewind(FILE *fp);

将文件位置指针指向文件首字节,即重置位置指针到文件首部

long ftell(FILE *fp);

用相对于文件起始位置的字节偏移量来表示返回的当前文件位置指针

int fflush(FILE *fp);

无条件地把缓存区中的所有数据写入物理设备

//L13-8

#include  <stdio.h>
#include  <stdlib.h>
typedef struct date     
{
    int   year;
    int   month;
    int   day;
}DATE;
typedef struct student
{
    long  studentID;            /* 学号 */
    char  studentName[10];         /* 姓名 */
    char  studentSex;            /* 性别 */
    DATE  birthday;                 /* 出生日期 */
    int      score[4];                 /* 4门课程的成绩 */
    float aver;                   /* 平均分 */
}STUDENT;
void SearchinFile(char fileName[], long k);
int main()
{
    long k;
    printf("Input the searching record number:");
    scanf("%ld", &k);    
    SearchinFile("student.txt", k);
    return 0;
}
/* 从文件fileName中查找并显示第k条记录的数据 */
void SearchinFile(char fileName[], long k)
{
    FILE *fp;
    int j;
    STUDENT stu;
    if ((fp = fopen(fileName,"r")) == NULL) /* 以读方式打开文本文件 */
    { 
        printf("Failure to open %s!\n", fileName);
        exit(0);
    }
    fseek(fp, (k-1)*sizeof(STUDENT), SEEK_SET);
    fread(&stu, sizeof(STUDENT), 1, fp); /* 按数据块读文件 */    
    printf("%10ld%8s%3c%6d/%02d/%02d", 
        stu.studentID, stu.studentName, stu.studentSex,
        stu.birthday.year, stu.birthday.month, stu.birthday.day);
    for (j=0; j<4; j++)
    {
        printf("%4d", stu.score[j]);
    }
    printf("%6.1f\n", stu.aver);    
    fclose(fp);        
}

标准输入/输出重定向:

  • 用"<"表示输入重定向
  • 用">"表示输出重定向
posted @ 2019-08-20 10:35  叮叮当当sunny  阅读(415)  评论(0编辑  收藏  举报