使用FILE结构操作文本文件(文件实训)

编写函数,该函数从已有的当前目录下的文件a.txt中读取并解析出其中的数值,并将结果写到当前目录下的文件b.txt中。

相关知识

文件文件是存储在某种长期储存设备(磁盘、光盘等)上的一段数据流。C 语言中把文件看成一个有序的字节流,每个文件都以文件结束标志( EOF )结束。
下图是包含 n 个字节的文件内容:
在这里插入图片描述
磁盘文件由操作系统中的文件系统统一管理,也只有文件系统才能直接操作文件。所以编写 C 程序来操作文件实际上是需要调用文件系统的接口函数来进行,我们学习文件的操作也就是学习一些 C 语言库中提供的函数。是不是感觉好简单啊:-)。

文件类型

C 语言在对文件进行操作时,将文件分为文本文件和二进制文件。

  1. 文本文件:指可以用任何文字处理程序阅读和编辑的简单 ASCII 文件;
  2. 二进制文件:指一般含有特殊的格式或计算机代码,如图形文件和可执行文件等。

文件的操作

C 语言中对文件的操作一般分为三个步骤:打开文件、读写文件、关闭文件。

打开文件

打开文件后,操作系统为文件建立一个文件控制结构(文件控制块),并在内存中建立一个缓冲区,该缓冲区的数据对应文件的数据,之后的文件读写操作实际上是在缓冲区中进行。

读写文件

通过文件控制块实现文件的输入输出。

关闭文件

将文件缓冲区中的数据写回到磁盘文件中,并释放文件控制块。
操作文件的函数用 FILE 结构操作文件是 C 语言提供的文件操作方式,只要包含头文件stdio.h就能使用文件操作的相关函数。下面就给大家介绍一些函数的使用。

打开文件

fopen 是stdio.h提供的文件打开函数。
如下面的程序可以打开一个文件用于读:

#include <stdio.h>
FILE *fp = fopen("a.txt","r");  // 打开一个供读取数据的文件a.txt。

其中函数的第一个参数是拟打开文件的路径和名字,可以包含相对路径或者绝对路径,如上面程序中就是打开当前目录下的a.txt文件。第二个参数是打开方式,fopen函数可以使用的打开方式如下表:

打开方式 描述
r 打开一个供读取数据的文件
w 建立或打开一个供写入数据的文件,如果该文件已经存在,则废弃文件内容
a 建立或打开一个供写入数据的文件,如果文件已经存在,则写入的数据将追加到文件的尾部
r+ 打开一个已存在的文件,该文件可以写入和读出数据
w+ 建立或打开一个可供读和写的文件,如果文件已存在,则废弃文件内容
a+ 建立或打开一个可供读和写的文件,如果文件已存在,则写入的数据追加到文件的尾部
b 打开一个二进制文件

如果文件打开成功,函数 fopen 将返回一个指向 FILE 结构的指针,该指针指向的 FILE 结构管理了被打开的那个文件。
如果文件打开失败(如打开一个不存在的文件用于读),那么该函数将返回 NULL。上面的程序将返回值赋值给FILE*的指针 fp ,之后就可以通过 fp 来操作打开的文件了。

读写文件

  1. 从文本文件中读取一个字符可以使用 fgetc 函数:
int fgetc(FILE *stream);

该函数表示从文件指针 stream 指向的文件的当前位置读取一个字符,并以 int 类型返回。

  1. 从文本文件读取一行可以使用 fgets 函数:
char *fgets(char *string, int n, FILE *stream);

该函数表示从文件指针 stream 指向的文件的当前位置开始读取字符串,直到遇到换行符(读入该换行符),或到达文件结束位置,或读取了 n-1 个字符。读取的字符串存入 string 所指的内存单元中,并在所有读取的字符之后添加字符串结束标记\0。
如果读取成功,函数返回 string,如果出错或读取前已经到达了文件结束的位置,将返回 NULL。

  1. 从文本文件中进行格式化读取可以使用 fscanf 函数:
int fscanf(FILE *stream, const char *format [,argument]...);

该函数的功能是从指定文件中将数据按照格式控制串 format 读出并转换成相应的类型以存入对应的参数中。如果读取成功,该函数返回转换成功的参数的个数,如果出错或读取前已经到达了文件结束的位置,将返回文件结束标志 EOF。
函数 fscanf 与 scanf 函数非常相似,只是 fscanf 函数多了一个参数 stream 以指向要读取数据的文件。

  1. 输出格式化数据到文本文件中可以使用 fprintf 函数:
int fprintf(FILE *stream, const char *format [,argument]);

该函数的功能是将数据按照格式控制串 format 写入到文件指针 stream 指向的文件中。如果写入成功,函数返回写入的字节数,否则返回一个负数表示错误。
函数 fprintf 与 printf 函数相似,只是 fprintf 函数多了一个参数 stream 以表示要写入数据的文件。

关闭文件

使用 fclose 函数就可以把缓冲区内最后剩余的数据输出到内核缓冲区,并释放文件指针和有关的缓冲区。
函数原型为:

int fclose(FILE *fp);

如果流成功关闭,fclose 返回0,否则返回 EOF(-1)。(如果流为NULL,而且程序可以继续执行,fclose设定error number给EINVAL,并返回EOF。)
例如:

#include <stdio.h>
int main()
{
   FILE *fp;
   fp = fopen("a.txt", "w");
   fprintf(fp, "%s", "www.educoder.net");
   fclose(fp);
   return(0);
}
//test.cpp
#include <stdio.h>
//声明外部函数,函数extractDigit在其它源文件中实现
extern void extractDigit();
int main()
{
 //准备文件a.txt的内容
 FILE *fp = fopen("a.txt","w");  //打开文件a.txt用于写
 char s[1000];
 fgets(s, 999, stdin);  //从键盘读取一行字符
 fputs(s,fp);  //将这一行字符写入文件a.txt中
 fclose(fp);   //关闭fp关联的文件a.txt
 extractDigit();  //调用函数,抽取数字写入文件b.txt中
 FILE *f = fopen("b.txt","r");  //以读的方式打开文件b.txt
 if(f==NULL)  //打开失败则返回
 {
  return 0;
 }
 int n,k=0; 
 fscanf(f,"%d",&n);  //从文件b.txt中读出一个整数到变量n中
 while(!feof(f))  //如果文件没结束(读出的不是EOF)
 {
  k++;
  printf("%d ",n);  //输出该整数到屏幕
  if(k%10==0)   //每十组一换行
  {
   printf("\n");
  }
  fscanf(f,"%d",&n);  //读取下一个整数
 }
 if(k%10!=10)  //最后一行没有换行符则补上
 {
  printf("\n");
 }
 return 0;
}
//fileTxt.cpp
#include <stdio.h>
// 函数extractDigit的功能:从文件a.txt中提取数值写入文件b.txt中
void extractDigit();
char readADigit(FILE *fi)
{
    char c = fgetc(fi);  // 从文件读取一个字符
    if(c==EOF)  // 是结束符则返回
    {
        return EOF;
    }
    while(c>'9' || c<'0')  // 如果不是数字字符,则继续读取下一个字符
    {
        c = fgetc(fi);  // 读取下一个字符
        if(c==EOF)  // 是结束符则返回
        {
            return EOF;
  	} 
    }
    return c;  // 返回读取的数字字符
}
// 函数extractDigit的功能:从文件a.txt中提取数值写入文件b.txt中
void extractDigit()
{
    FILE *fi = fopen("a.txt","r");  // 以读的方式打开文件a.txt
    FILE *fo = fopen("b.txt","w");  // 以写的方式打开文件b.txt
    if(fi==NULL || fo==NULL)  // 如果某个文件打开失败,则返回
    {
        return;
    }    
    char c;
    int num=0,k=0;
    c = readADigit(fi);  // 读取一个数字字符
    while(c!=EOF)
    {
        num=num*10+c-'0';  // 计算数字字符构成的整数
        k++;
        if(k==3)  // 已经三位了
        {
            fprintf(fo,"%d ",num);  // 将计算的整数写入文件指针fo指向的文件
            k=0;  // 重新计数
            num=0;  // 重新计算
     }
        c = readADigit(fi);  // 读取下一个数字字符
    }
    if(k!=0)  // 如果有不到三位的数值,则写入文件b.txt
    {
        fprintf(fo,"%d ",num);
    }
    fclose(fi);  // 关闭文件fi
    fclose(fo);  // 关闭文件fo
}
原创文章 291 获赞 256 访问量 2万+

猜你喜欢

转载自blog.csdn.net/huangziguang/article/details/105850545