C语言文件操作

文件

  1. 程序文件(程序代码)
  2. 数据文件(电脑中普遍用于存储各种东西的文件)
  • “文件”一般是 指储存再外部介质上数据的集合。
  • 操作系统是以文件为单位对数据进行管理的。
  • 如果想找存放在外部介质上的数据,必须先按文件名找到所指定的文件,然后再从文件中读取数据。
  • 要向外部介质上储存数据也必须先建立一个文件(以文件名作为标志),才能向它输出数据。

输入输出是数据传送的过程,数据如流水一样从一处留下另一处,因此常将输入输出形象地称为,即数据流流表示了信息从源到目的端的流动。

文件名

一个文件有一个唯一的文件标识。它由3部分组成:文件路径,文件名主干,文件后缀。

例如D:\CC\temp\filel.da为一个文件标识

它常被称为文件名。注意要和文件名主干相区别,前面的例子中整体为文件名,而filel是文件名主干,我们通常自己命名的部分就是文件名主干。

文件的分类

  • ASCII文件(文本文件)
  • 二进制文件(映像文件)

其他与文件操作相关的简单概念名词

文件缓冲区

文件类型指针

文件操作相关函数

打开用fopen函数,关闭用fclose函数。

读取一个字符用fgetc函数,读入一个字符用fputc函数

读取一个字符串用fgets函数,读入一个字符串用fputs函数

检测是否读完了文件用feof函数

格式化方式读写文本文件用fprintf函数fscanf函数

二进制方式读写文本文件用fread函数fwrite函数

使文件位置标记指向开头用rewind函数,改变文件位置标记用fseek函数

测定文件当前位置标记用ftell函数

排查输入输出错误用feeror函数,排查文件出错标志和结束标志用clearerr函数

带b就是与二进制文件相关。 

--------------------------------------------------------------------------------------------------------------------------------

分别介绍

fopen函数

FILE *fopen(const char *filename, const char *mode) 使用给定的文件使用方式 mode 打开 filename 所指向的文件。

FILE *fopen(const char *filename, const char *mode)

  • filename -- 这是 C 字符串,包含了要打开的文件名称。
  • mode -- 这是 C 字符串,包含了文件使用方式。

fclose函数

int fclose(FILE *stream) 关闭流 stream。刷新所有的缓冲区。

  • stream -- 这是指向 FILE 对象的指针(即文件指针),该 FILE 对象指定了要被关闭的流。

如果流成功关闭,则该方法返回零。如果失败,则返回 EOF。

fgetc函数

int fgetc(FILE *stream) 从指定的流 stream 获取下一个字符(一个无符号字符),并把位置标识符往前移动。

该函数以无符号 char 强制转换为 int 的形式返回读取的字符,如果到达文件末尾或发生读错误,则返回 EOF。

fputc函数

int fputc(int char, FILE *stream) 把参数 char 指定的字符(一个无符号字符)写入到指定的流 stream 中,并把位置标识符往前移动。

  • char -- 这是要被写入的字符。该字符以其对应的 int 值进行传递。 

如果没有发生错误,则返回被写入的字符。如果发生错误,则返回 EOF,并设置错误标识符。

fgets函数

char *fgets(char *str, int n, FILE *stream) 从指定的流 stream 读取一行,并把它存储在 str 所指向的字符串内。当读取 (n-1) 个字符时,或者读取到换行符时,或者到达文件末尾时,它会停止,具体视情况而定。

  • str -- 这是指向一个字符数组的指针,该数组存储了要读取的字符串。
  • n -- 这是要读取的最大字符数(包括最后的空字符)。通常是使用以 str 传递的数组长度。

如果成功,该函数返回相同的 str 参数。如果到达文件末尾或者没有读取到任何字符,str 的内容保持不变,并返回一个空指针,如果发生错误,返回一个空指针。

fputs函数

int fputs(const char *str, FILE *stream) 把字符串写入到指定的流 stream 中,但不包括空字符。

  • str -- 这是一个数组,包含了要写入的以空字符终止的字符序列。

该函数返回一个非负值,如果发生错误则返回 EOF。

feof函数

int feof(FILE *stream)  测试给定流 stream 的文件结束标识符。

当设置了与流关联的文件结束标识符时,该函数返回一个非零值,否则返回零。

fprintf函数

int fprintf(FILE *stream, const char *format, ...) 发送格式化输出到流 stream 中。 

  • format -- 这是 C 字符串,包含了要被写入到流 stream 中的文本

如果成功,则返回写入的字符总数,否则返回一个负数。

fscanf函数

 int fscanf(FILE *stream, const char *format, ...) 从流 stream 读取格式化输入。

如果成功,该函数返回成功匹配和赋值的个数。如果到达文件末尾或发生读错误,则返回 EOF。

fread函数

size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream) 

从给定流 stream 读取数据到 ptr 所指向的数组中。

  • ptr -- 这是指向带有最小尺寸 size*nmemb 字节的内存块的指针
  • size -- 这是要读取的每个元素的大小,以字节为单位。
  • nmemb -- 这是元素的个数,每个元素的大小为 size 字节。

成功读取的元素总数会以 size_t 对象返回,size_t 对象是一个整型数据类型。如果总数与 nmemb 参数不同,则可能发生了一个错误或者到达了文件末尾。

fwrite函数

size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream) 

把 ptr 所指向的数组中的数据写入到给定流 stream 中。

  • ptr -- 这是指向要被写入的元素数组指针
  • size -- 这是要被写入的每个元素的大小,以字节为单位。
  • nmemb -- 这是元素的个数,每个元素的大小为 size 字节。

如果成功,该函数返回一个 size_t 对象,表示元素的总数,该对象是一个整型数据类型。如果该数字与 nmemb 参数不同,则会显示一个错误。

rewind函数

void rewind(FILE *stream) 设置文件位置标记为给定流 stream 的文件的开头。

该函数不返回任何值。

fseek函数

 int fseek(FILE *stream, long int offset, int whence) 设置流 stream 的文件位置标记为给定的偏移 offset,参数 offset 意味着从给定的 whence 位置查找的字节数。

  • offset -- 这是相对 whence 的偏移量,以字节为单位。
  • whence -- 这是表示开始添加偏移 offset 的位置。它一般指定为下列常量(0,1,2)之一:
起始点名字用数字表示
文件开头位置SEEK_SET0
文件当前位置SEEK_CUR1
文件末尾位置SEEK_END2

如果成功,则该函数返回零,否则返回非零值

ftell函数

long int ftell(FILE *stream) 返回给定流 stream 的当前文件位置

该函数返回位置标识符的当前值。如果发生错误,则返回 -1L,全局变量 errno 被设置为一个正值

feeror函数

 int ferror(FILE *stream) 测试给定流 stream 的错误标识符。

如果设置了与流关联的错误标识符,该函数返回一个非零值,否则返回一个零值。

clearerr函数

void clearerr(FILE *stream)  清除给定流 stream 的文件结束和错误标识符。

这不会失败,且不会设置外部变量 errno,但是如果它检测到它的参数不是一个有效的流,则返回 -1,并设置 errno 为 EBADF。

一些实际应用


1.从键盘输入一些字符,并把它们送到磁盘上去,直到用户输入一个“#“为止。
用fgetc函数从键盘逐个输入字符,然后用fgetc函数写到磁盘文件上即可。

#include<stdio.h>
#include<stdlib.h>
int main()
{
    FILE *fp;
    char ch,filename[100];
    printf("请输入所用的文件名:");
    scanf("%s",filename);
    getchar();
    if((fp=fopen(filename,"w"))==NULL)
    {
        printf("cannot open file\n");
        exit(0);
    }
    printf("请输入一个准备储存到磁盘发字符串(以#结束):");

    ch=getchar();//接收从键盘输入的第一个字符
    while(ch != '#')
    {
        fputc(ch,fp);
        putchar(ch);
        ch=getchar();//再接受从键盘输入的一个字符
    }
    fclose(fp);
    putchar(10);//向屏幕输出一个换行符

    return 0;
}

2.将一个磁盘文件中的信息复制到另一个磁盘文件中。今要求将上例建立的file1.dat文件中的内容复制到另一个磁盘filel.2.dat中。

从file1.dat文件中逐个读入字符,然后逐个输出到filel.2.dat中。

#include<stdio.h>
#include<stdlib.h>
int main()
{
    FILE *in,*out;
    char ch,infile[100],outfile[100];
    printf("请输入读入文件名字:");
    scanf("%s",infile);
    printf("请输入读出文件名字:");
    scanf("%s",outfile);
    if((in=fopen(infile,"r"))==NULL)
    {
        printf("cannot open file\n");
        exit(0);
    }
    if((out=fopen(outfile,"w"))==NULL)
    {
        printf("cannot open file\n");
        exit(0);
    }
    ch=fgetc(in);
    while(!feof(in))
    {
        fputc(ch,out);
        putchar(ch);
        ch=fgetc(in);
    }
    putchar(10);
    fclose(in);
    fclose(out);
    return 0;
}

3.从键盘读入若干个字符串,对它们按字母大小的顺序排序,然后把排好序的字符串送到磁盘文件中保存。(假设已经建立了文件E:\string.txt)

  • 从键盘读入n个字符串,存放在一个二维字符数组中,每个一维数组存放一个字符串
  • 对字符数组中的n个字符串按字母顺序排序,排好序的字符串仍放在字符数组中
  • 将字符数组中的字符串顺序输出
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
    FILE *fp;

    int i,j,k,n=3;
    char str[n][10],temp[10];
    printf("Enter strings:\n");
    for(i=0;i<n;i++)
        gets(str[i]);

    for(i=0;i<n-1;i++)//选择排序法对字符串排序
    {
        k=i;
        for(j=i+1;j<n;j++)
            if(strcmp(str[k],str[j])>0)k=j;
        if(k!=i)
        {
            strcpy(temp,str[i]);
            strcpy(str[i],str[k]);
            strcpy(str[k],temp);
        }
    }
    if((fp=fopen("E:\\string.txt","w"))==NULL)//注意转义字符
    {
        printf("cannot open file\n");
        exit(0);
    }
    printf("\nThe new sequence:\n");
    for(i=0;i<n;i++)
    {
        fputs(str[i],fp);
        fputs("\n",fp);
        printf("%s\n",str[i]);
    }
    return 0;
}

编写以下程序,可以从文件string.txt中读回字符串,并在屏幕上显示

#include<stdio.h>
#include<stdlib.h>
int main()
{
   FILE *fp;
   char str[3][10];
   int i=0;
   if((fp=fopen("E:\\string.txt","r"))==NULL)
   {
       printf("cannot open file\n");
       exit(0);
   }
   while(fgets(str[i],10,fp)!=NULL)
   {
       printf("%s",str[i]);
       i++;
   }
   fclose(fp);
   return 0;
}

4.从键盘输入10个学生的有关数据,然后把它们转存到磁盘文件上去。

定义一个有10个元素的结构体数组,用来存放10个学生的数据。从main函数输入10个学生的数据,用save函数实现向磁盘输出学生数据。用fwrite函数一次输出一个学生的数据。

假设输入数据为

Zhang 1001 19 room_101
Sun 1002 20 room_102
Tan 1003 21 room_103
Lin 1004 20 room_104
Wu 1005 18 room_105
Huang 1006 19 room_106
Zhan 1007 18 room_107
Luo 1008 19 room_108
Ke 1009 22 room_109
Qin 1010 21 room_110

#include<stdio.h>
#define SIZE 10

struct Student_type
{
    char name[10];
    int num;
    int age;
    char addr[15];
}stud[SIZE];

void save()
{
    FILE * fp;
    int i;
    if((fp=fopen("stu.dat","wb"))==NULL)
    {
        printf("cannot open file\n");
        return;
    }
    for(i=0;i<SIZE;i++)
        if(fwrite(&stud[i],sizeof(struct Student_type),1,fp)!=1)
            printf("file write error\n");
    fclose(fp);
}

int main()
{
    int i;
    printf("Please enter data of students :\n");
    for(i=0;i<SIZE;i++)
    scanf("%s%d%d%s",stud[i].name,&stud[i].num,&stud[i].age,stud[i].addr);
    save();
    return 0;
}

在fopen函数中指定读写方式为wb,即二进制写方式。在向磁盘文件stu.dat写的时候,将内存中存放stud数组元素stud[i]的内存单元中的内容原样复制到磁盘文件中,所建立的stu.dat文件是一个二进制文件。这个文件可以为其他文件所用

在本程序中,用fopen函数打开文件时没有指定路径,只写了文件名stu.dat,系统默认其路径为当前路径为当前用户所使用的子目录(即源文件所在的目录),在此目录下建立一个新文件stu.dat,输出的数据存放在此文件中。 

//以下程序可以检查是否读入准确

#include<stdio.h>
#include<stdlib.h>
#define SIZE 10

struct Student_type
{
    char name[10];
    int num;
    int age;
    char addr[15];
}stud[SIZE];

int main()
{
    int i;
    FILE * fp;
    if((fp=fopen("stu.dat","rb"))==NULL)
    {
        printf("cannot open file\n");
        exit(0);
    }
    for(i=0;i<SIZE;i++)
    {
        fread(&stud[i],sizeof(struct Student_type),1,fp);
        printf("%-10s %4d %4d %-15s\n",stud[i].name,stud[i].num,stud[i].age,stud[i].addr);
    }
    fclose(fp);
    return 0;
}

5.有一个磁盘文件,内有一些信息。要求第一次将它的内容显示在屏幕上,第二次把它复制到另一个文件上。

解题思路:两个问题都不难,但是把两者连续做,就会出现问题,因为在第一次读入完文件后,文件位置标记已指到文件的末尾,如果再接着读数据,就遇到文件结束标志EOF,feof函数的值等于1(为真),无法再读入数据。必须在程序中用rewind函数使位置指针返回文件开头。

#include<stdio.h>
int main()
{
    FILE *fp1,*fp2;
    char ch;
    if((fp1=fopen("file1.dat","r"))==NULL)
    {
        printf("cannot open file\n");
        exit(0);
    }
    if((fp2=fopen("file2.dat","w"))==NULL)
    {
        printf("cannot open file\n");
        exit(0);
    }
    ch=fgetc(fp1);
    while(!feof(fp1))
    {
        putchar(ch);
        ch=fgetc(fp1);
    }
    putchar(10);
    rewind(fp1);
    ch=fgetc(fp1);
    while(!feof(fp1))
    {
        fputc(ch,fp2);
        ch=fgetc(fp1);
    }
    fclose(fp1);fclose(fp2);
    return 0;
}

6.在磁盘文件上存有10个学生的信息,要求将第1,3,5,7,9个学生数据输入计算机,并在屏幕上显示出来。

思路:

  • 按“二进制只读”的方式打开指定的磁盘文件,准备从磁盘文件中读取学生学习
  • 将文件位置标记指向文件的开头,然后从磁盘文件读取一个学生的信息,并把它显示在屏幕上
  • 再将文件位置标记指向文件中第3,5,7,9个学生数据区的开头,从磁盘文件读入相应学生的信息,并把它显示在屏幕上。

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

struct Student_type
{
    char name[10];
    int num;
    int age;
    char addr[15];
}stud[10];

int main()
{
    int i;
    FILE *fp;
    if((fp=fopen("stu.dat","rb"))==NULL)
    {
        printf("cannot open file\n");
        exit(0);
    }
    for(i=0;i<10;i=i+2)//题目要求的是第3,5,7,9个学生的数据
    {
        fseek(fp,i*sizeof(struct Student_type),0);//移动文件为位置标记
        fread(&stud[i],sizeof(struct Student_type),1,fp);//读一个数据块到结构体变量
        printf("%-10s %4d %4d %-10s\n",stud[i].name,stud[i].num,stud[i].age,stud[i].addr);//在屏幕输出
    }
    fclose(fp);
    return 0;
}

 要瞎了要瞎了,溜了溜了

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值