C语言学习——文件详解

C语言学习——文件详解

1 C文件概述

按照某个规则集合在一起,保存在外部存储器上的一批数据称为“文件”。目前计算机中的外部存储器主要是磁盘,所以常把文件称为“磁盘文件”。
由于文件存放在外部存储器中,计算机关闭后文件中的数据并不丢失。文件能长期保存数据的这个特点是文件的主要用途之一。

1.1 C文件

C 语言中的文件是由若个数据按照写入时的顺序组合在一起,每个数据都可以是字符型、整型、实型、字符串型、指针型、结构型等。

C 语言文件的主要操作有两种:
一是将变量、数组元素等对象中的数据依次存放到文件中,称为“写文件”;
二是读取文件中的数据存到变量、数组元素等对象中,称为“读文件”。

在C语言中,读写文件中的数据全部使用系统提供的各种文件读写函数。

1.2 文件名

文件名是文件的标识,用于区别外部存储器上的不同文件。

文件名的一般组成如下:
盘符: 路径文件主名.扩展名。

其中:
“盘符”可以是A、B、C、D等,盘符表示文件所在的磁盘。
“路径”形如“\文件夹\文件夹…\”,路径是用来表示文件所在的文件夹。
“文件主名”是由字母开头的字母数字等字符组成的,字母不分大小写。
“扩展名”是由字母开头的字母数字等字符组成的,字母不分大小写。
常用的扩展名有:c(C 源程序文件)、exe(可执行程序文件)、txt(文本文件)、dat(数据文件)。

注意:组成文件名时,“盘符”和“路径”都可以省略。省略时的规定如下:
(1)仅省略“盘符”,表示在当前盘指定路径下寻找文件。
(2)仅省略“路径”,表示文件在指定盘的当前路径下寻找文件。
(3)同时省略“盘符”和“路径”,则表示在当前盘当前路径下寻找文件。
(4)在VC++ 6.0 的环境下,当前盘是指当前处理的源程序文件所在的磁盘;当前路径是指当前处理的源程序文件所在的路径。

1.3 ASCII 码文件(文本文件)与二进制文件

⑴ASCII 码文件(文本文件):文件的每一个字节放 一个ASCII代码,代表对应的字符。
⑵二进制文件 :数据按其内存中的存储形式原样存储在文件中: 1个字节存放1个字符; 2个字节存放1个短整数;4个字节存放1个长整数/单精度实数; 8个字节存放1个双精度实数等…………
在这里插入图片描述
在这里插入图片描述

文件的输入输出方式
⑴非缓冲文件系统∶程序与外设直接进行数据交换。
特点∶每读写一次都要启动外设。

⑵缓冲文件系统∶程序与外设通过内存缓冲区进行数据交换
特点∶只有内存缓冲区满(写盘)或空(读盘)才启动外设。

在这里插入图片描述
根据数据读写方式不同可分为两类文件∶

  • 顺序存取文件
  • 随机存取文件

文件的基本操作

  1. 定义一个FILE类型指针
  2. 打开文件∶把文件数据从磁盘上读入内存缓存
  3. 读写文件∶从内存缓存读写文件
  4. 关闭文件∶把内存中的缓存数据存入磁盘

使用文件前必须定义一个FILE类型指针
FILE *fp;
当文件打开后,系统自动建立文件结构信息,并返回一个指向它的指针fp。程序通过fp访问文件获得文件信息。
“FILE”是在头文件“stdio.h”中定义的, 所以使用它的程序开头必须写上包含命令#include “stdio.h”。

【例 】 文件型指针变量的定义示例。
#include “stdio.h”
FILE *fp1,file_p1;
/
定义2 个文件型指针变量:fp1和 file_p1 */
所定义的每个文件型指针变量可以指向一个文件,并利用已经指向具体文件的文件型指针变量来处理对应文件中的数据。

2 文件的打开与关闭

由于程序只能处理内存(即程序中的变量、数组等)中的数据,不能直接处理磁盘上文件中的数据。只有把文件中的数据读取到内存中,才能通过程序来处理这些数据。

同样,修改文件中的数据,必须先将数据读到内存中,然后修改。由于修改的是内存中的数据,还需要将内存中的数据存回到磁盘上,才能保证文件中的数据被修改。

通常把“从文件中读取数据到内存”称为“文件的打开” ;
把“内存中的数据存回到文件中”称为“文件的关闭” 。因此,文件使用之前要打开;使用后必须关闭。

2.1 文件打开函数 fopen()

函数调用格式: fopen(filename,mode)
函数形式参数: filename 存放磁盘文件名的字符串的首地址。
mode存放文件使用方式的字符串的首地址。
函数功能: 以“mode”指定的文件使用方式,打开“filename ”指定的文件。
函数返回值: 正确打开文件,则返回只能用文件型指针变量接受的内存地址; 否则返回NULL。NULL 是在“stdio.h ”中定义的符号常量,值为0 。
例∶ fp=fopen(“stu.dat”,“rb”);

在这里插入图片描述

2.2 文件关闭函数 fclose( )

函数调用格式: fclose(fp)
函数形式参数: fp 已指向某个打开文件的文件型指针变量。
函数功能: 关闭 fp 所指向的文件,同时自动释放分配给该文件的内存缓冲区。
函数返回值: 能正确关闭指定的文件,则返回 0;否则返回非 0 整数。

注意,本函数的参数必须是指向某个已经打开文件的文件型指针变量。

2.3 中止程序运行函数 exit()

函数调用格式: exit(0)
**函数功能:**强迫中止当前程序的继续运行,自动关闭所有已经打开的文件。
使用本函数的程序清单开头应写上下列包含命令:
#include “stdlib.h”

本函数主要用在文件操作时出现错误,无法继续程序的执行时,使用本函数可以强迫中止程序执行,同时能自动关闭所有已经打开的文件。

在这里插入图片描述

3 文件的读写

当程序中以合适的方式打开了文件,就可以对文件进行写数据或读数据的操作。

对文件中的数据进行写读时,可以想象有一个“文件内部指针”指向文件中的某个数据,当向文件中写入数据后,这个内部指针总是自动指向下一个要写入数据的位置。当读取数据后,内部指针会自动指向下一个数据。这个内部指针随着文件的打开而自动设置,随着文件的关闭将自动消失。

注意,所有写读操作都是通过系统函数来完成的。本节介绍的所有文件写读的系统函数均包含在头文件“stdio.h ”中。

3.1 文件尾测试函数 feof()

在程序中读取文件的数据时,需要判断是否到达文件尾。若到达文件尾,则不能继续取数据。系统提供的文件尾测试函数可以帮助用户判断是否到达文件尾。

函数调用格式: feof(fp)
函数形式参数: fp 指向已打开文件的文件型指针变量。
函数功能: 测试 fp 所指向文件是否到达文件尾。通过函数返回值获得测试结果。
函数返回值: 若当前是文件尾,返回非 0;否则返回 0。

3.2 字符写、读函数 fputc()、fgetc()

字符写读函数在处理文件中数据时,是以字符(即 1 字节数据)为单位的,即每次仅写读 1 个字符。因此,所处理的文件一般是文本文件,但也可以是二进制文件。对二进制文件写读数据时,每次写读某个数据中的 1 个字节值。

3.2.1 将字符写入文件的函数 fputc()

函数调用格式:fputc(ch,fp)
函数形式参数:ch 写到文件中的字符,可以是字符常量、字符变量、字符型表达式等。
fp 指向已打开的可写文件的文件型指针变量。
函数功能: 将 ch 中的字符写到 fp 所指向的文件的当前位置。
函数返回值:正确,则返回刚写到文件中的字符;
错误,则返回 EOF。EOF是在“stdio.h”中定义的符号常量,值为−1。

【例 】  从键盘上读取 15 个字符,写到名为“ccw1.txt”的文本文件中。 

#include "stdio.h" 
#include "stdlib.h" 
void main(void) 
{ FILE *fp1;                                   /* 定义文件型指针变量 */ 
  int i; 
  char ch; 
  if ((fp1=fopen("ccw1.txt","w"))==NULL)      /* 打开文本文件用于写 */ 
        { printf("File can not open!\n"); 
          exit(0); 
        } 
  for (i=0;i<15;i++)                       /* 15 次循环 */ 
       { ch=getchar();  fputc(ch,fp1);      /* 从键盘读取字符写入文件 */ 
       } 
  fclose(fp1);                               /* 关闭文件 */ 
} 
3.2.2从文件中读取字符的函数 fgetc()

函数调用格式: fgetc(fp)
函数形式参数: fp 指向已打开的可读文件的文件型指针变量。
函数功能: 从 fp 所指向的文件当前位置读取单个字符。
函数返回值: 正确,则返回读取的单个字符(或 1 字节值) ;错误,则返回 EOF(−1)。

【例 】  从[例 8-6]中建立的名为“ccw1.txt”的文本文件中读取前 10 个字符显示。  
#include "stdio.h" 
#include "stdlib.h" 
void main() 
{ FILE *fp1;                                   /* 定义文件型指针变量 */ 
  int i; 
  char ch; 
  if ((fp1=fopen("ccw1.txt","r"))==NULL)      /* 打开文本文件用于读 */ 
        { printf("File can not open!\n"); 
          exit(0); 
        } 
  for (i=0;i<10;i++)                           /* 10 次循环 */ 
       { ch=fgetc(fp1);           /* 从文件中读取1个字符存入变量ch */ 
          putchar(ch);             /* 将变量ch 中字符输出到显示器 */ 
       } 
  fclose(fp1); 
} 

3.3 数据块写、读函数 fwrite()、fread()

数据块写读函数在处理文件中数据时,是以字节数已经确定的“一块”数据为单位,每次可写读若干“块”数据。因此,所处理的文件一般是二进制文件,也可以是文本文件。

用数据块写读函数写读文本文件时,通常“一块”数据是 1个字节;写读短整型数据时,通常“一块”数据是 2 个字节;写读长整型数据、单精度实型数据时,通常“一块”数据是4 个字节;写读双精度实型数据时,通常“一块”数据是 8 个字节;写读结构体数据时,通常“一块”数据是 sizeof(struct 结构体名)个字节。由此看出,本函数能写读各种类型的数据。

3.3.1 将数据块写入文件的函数 fwrite()

*函数调用格式: *fwrite(buf,size,n,*fp)
函数形式参数:
buf 存放待写入文件的数据的内存区域首地址,例如变量的地址、数组元素的地址、数组首地址、指向能存放数据的内存地址的指针变量等。
size 无符号整型,可以是常量、变量或表达式。表示“每块”数据的字节数,通常使用“sizeof(数据类型符)” 。
n 无符号整型,可以是常量、变量或表达式。表示每次写入“块数” 。
fp 指向已打开的可写文件的文件型指针变量。

函数功能: 将 buf指向内存区域中 n×size 个字节的数据写入 fp所指向的文件。
函数返回值: 正确,则返回 n 值;错误,则返回 NULL(0)。

3.3.2 从文件中读取数据块的函数 fread()

函数调用格式:fread(buf,size,n,fp)
函数形式参数:
buf 存放数据的内存区域首地址,例如变量地址、数组元素地址、数组首地址、指向能存放数据的内存地址的指针变量等。
size 无符号整型,可以是常量、变量或表达式。表示“每块”数据的字节数,通常使用“sizeof(数据类型符)” 。
n 无符号整型,可以是常量、变量或表达式。表示每次读取“块数” 。
fp 指向已打开的可读文件的文件型指针变量。

函数功能: 从 fp 所指向的文件当前位置读取 n×size 个字节的数据,组成 n 个长度为 size的数据块存入 buf指定的内存区。
函数返回值:正确,则返回 n 值;错误,则返回 NULL(0)。

3.4 格式数据写、读函数 fprintf()、fscanf()

格式数据写读函数和格式化输入、输出函数 scanf()、printf()类似,可以控制写读文件中数据的格式,包括数据类型、数据宽度、实数的小数位数等。所处理的文件是文本文件。

3.4.1 将格式化数据写入文件的函数 fprintf()

函数调用格式: fprintf(fp,format,e1,e2,…,en)
函数形式参数:fp 指向已打开的可写文件的文件型指针变量。
format 输出格式字符串。 Ei指表达式。
函数功能:计算表达式表“e1,e2,…,en”中每个表达式的值,按照 format 对应的“输出格式字符串”中指定的格式,写入 fp 指向的文件。
函数返回值:正确,则返回写入文件的表达式数目;错误,则返回 EOF(−1)。

3.4.2 从文件中读取格式化数据的函数 fscanf()

函数调用格式:fscanf(fp,format,add1,add2,…,addn)
函数形式参数:
fp 指向已打开的可读文件的文件型指针变量。
format 输入格式字符串。
addi 地 址。
函数功能:按照 format 对应的“输入格式字符串”中指定的格式,从 fp 指向的文件中读取 n 个数据依次存入 add1、add2、…、addn 对应的地址中。
函数返回值:正确,则返回读取数据的数目;错误,则返回 EOF(−1)。

3.5 字符串写、读函数 fputs()、fgets()

字符串写读函数在读写文件中数据时,是以字符串为单位的,即每次仅写读 1 个字符串。因此,所处理的文件是文本文件。

3.5.1.将字符串写入文件的函数 fputs()

函数调用格式:fputs(str,fp)
函数形式参数:
str 存放待写入文件的字符串的内存区域首地址。
fp 指向已打开的可读文件的文件型指针变量。
函数功能:将 str处存放的一个字符串写入 fp所指向的文本文件中。 写入文件时,字符串结束标记符’\0’并不写入文件。

3.5.2 从文件中读取字符串的函数 fgets()

函数调用格式: fgets(str,n,fp)
函数形式参数:
str 存放从文件中读取的字符串的首地址。
n 整型,可以是整型常量、整型变量、整型表达式。
fp 指向已打开的可读文件的文件型指针变量。
函数功能: 从 fp 所指向的文件当前位置读取 n−1 个字符,在其后补充一个字符串结束标记符’\0’,组成字符串后存入 str指定的内存区。
如果读取的前 n−1 个字符中有回车换行符’\n’,则只读到回车换行符为止,补充字符串结束标记符’\0’,组成字符串(包括该回车符) ,存入 str指定的内存区。
如果读取的前n−1个字符中遇到文件尾, 则在读取的字符后面补充字符串结束标记符’\0’,组成字符串存入 str指定的内存区。
函数返回值:正确,则返回 str对应的地址;错误,则返回 NULL(0)。

4 文 件 的 定 位

读取文件中的数据时,每次都需要从文件头开始。为了能从文件中直接读取某个数据,系统提供了能将文件内部指针直接定位到某个字节上,从而实现了随机读取文件中数据的功能。

4.1 文件头定位函数 rewind()

文件头定位函数的主要功能是将文件内部指针重新指向文件头。

函数调用格式: rewind(fp)

函数形式参数
fp 指向已打开文件的文件型指针变量。

函数功能:将 fp 所指向文件的内部指针重新指向文件开头。

函数返回值:正确,返回 0;错误,则返回非 0。

【例 】  从键盘上读取 15个字符,写入名为“CCW1.TXT”的文本文件中。然后从文件中读取前 10 个字符显示。
#include "stdio.h" 
#include "stdlib.h" 
void main() 
{ FILE *fp;                                 /* 定义文件型指针变量 */ 
  int i; 
  if ((fp=fopen("ccw1.txt","w+"))==NULL)   /* 打开文本文件用于写读 */ 
      { printf("File can not open!\n");   exit(0);   } 
  for (i=0;i<15;i++)                     /* 15 次循环 */ 
       fputc(fgetc(stdin),fp);             /* 从键盘读取字符写入文件 */ 
  rewind(fp);                             /* 让内部指针重新指向文件头 */ 
  for (i=0;i<10;i++)                      /* 10 次循环 */ 
        fputc(fgetc(fp),stdout);     /* 从文件中读取1个字符输出到显示器 */ 
  fclose(fp); 
} 

4.2 随机定位函数 fseek()

随机定位函数的功能是将文件内部指针指向偏离某个基准点若干个字节的新位置。
函数调用格式:fseek(fp,offset,from)
函数形式参数: fp 指向已打开文件的文件型指针变量。
offset 长整型表达式,重新定位时的偏移字节数。
from 重新定位时的基准点,可以选用下列的整数或符号常量:

在这里插入图片描述函数功能:将 fp 所指向的文件内部指针从 from 指定的起始位置移动 offset 个字节,指向新的位置。
函数返回值:正确,返回 0;错误,则返回非 0。

【例】从键盘上读取10个学生的信息(学号、姓名、总分),写到“s_list.dat”的二进制文件中,关闭该文件。打开“s_list.dat”的二进制文件,从中查找总分最高的学生,并输出其有关信息。
  算法:定义结构型,以及存放学生信息的结构型变量;
        只写方式打开文件;
        for型循环:输入一个学生信息,存入文件。关闭文件。
        只读方式打开文件,读取一个学生信息作为当前最高分,并记录该生信息。
        当型循环:读取一个学生信息,与当前最高分比较,记录新的最高分学生信息。
        输出最高分的学生有关信息。
程序:#include “string.h”
#include "stdio.h"
struct student  { long num;        /*学号*/
                  char name[10];   /*姓名*/
                  float total;     /*总分*/
                } s[10],s1,max;
main()
{ FILE *fp;    int i,j;     float x;
  for (i=0;i<10;i++)                                    /*输入10个学生的信息*/
      { scanf("%s",s[i].name);                          /*输入姓名*/
        scanf(%ld,%f”,&s[i].num,&x); s[i].total=x;     /*输入学号、总分*/
      }
if ((fp=fopen(“s_list.dat","wb"))==NULL)            /*打开只写二进制文件*/
     { printf("File can not open!\n");  exit(0); }
  fwrite(s,sizeof(struct student),10,fp);      /*10个学生信息写到fp指向文件*/
  fclose(fp); /*关闭fp所指向的文件*/
  if ((fp=fopen(“s_list.dat”,“rb”))==NULL)            /*打开只读二进制文件*/
     { printf("File can not open!\n");  exit(0); }
  fread(&max,sizeof(struct student),1,fp);   /* 读取第1个学生信息 */
  while (!feof(fp))                    /* 当型循环寻找最高分学生 */
        { fread(&s1,sizeof(struct student),1,fp);
          if (max.total<s1.total)
             { max.num=s1.num;
               strcpy(max.name,s1.name);
               max.total=s1.total;
             }
        }                
  fclose(fp);                                       /* 关闭文件 */
  printf(%-10ld%-10s%-10.2f\n”,max.num,max.name,max.total); /* 输出 */
}
  • 7
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值