C (第十四章 文件操作)

平凡无常的一天在自律中砥砺前行, 才着实充实!

14. 文件操作

14.1 C文件的有关基本知识
14.1.1 文件的定义
  • 程序文件:包括源程序文件(后缀为.c),目标文件(后缀为.obj),可执行程序(windows环境后缀为.exe)。
  • 数据文件:程序运行需要从中读取数据的文件,或者输出内容的文件。
14.1.2 文件名
  • 一个文件要有唯一的文件标识,以便用户识别和引用。
  • 文件包含:文件路径 + 文件主干名 + 文件后缀
例如:/home/yangjie/hello_world.cpp
14.1.3 文件的分类

根据数据的组织形式,文件可分为文本文件和二进制文件

  • 二进制文件:数据在内存中以二进制的形式存储,如果不加转换的输出到外存,即为二进制文件。
  • 文本文件:
14.1.4 文件缓冲系统
  • 指操作系统自动地在内存中为每一个正在使用的文件开辟一块“文件缓冲区”。
  • 从内存像磁盘输出数据首先会送到内存中的缓冲区,装满缓冲区之后才一起送到磁盘上。
  • 缓冲区的大小是根据C编译系统决定的。
    在这里插入图片描述
14.1.5 文件类型指针 (文件指针)
  • 缓冲文件系统中,每个被使用的文件都在内存中开辟了一个相应的文件信息区,用来存放文件的相关信息(例如文件的名字,文件状态以及文件当前的位置等)。
  • 这些信息都保存在一个结构体变量中的,该结构体类型是系统声明的,取名FILE。
14.2 打开与关闭文件
14.2.1 fopen() 函数打开数据文件

描述

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

声明

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

参数

  • filename – 这是 C 字符串,包含了要打开的文件名称。
  • mode – 这是 C 字符串,包含了文件访问模式,模式如下:
模式描述
“r”打开只读文件,该文件必须存在
“r+”打开可读写的文件,该文件必须存在
“rb+”读写打开一个二进制文件,只允许读写数据
“rt+”读写打开一个文本文件,允许读和写
“w”打开只写文件,若文件存在则文件长度清为0,即该文件内容会消失。若文件不存在则建立该文件
“w+”打开可读写文件,若文件存在则文件长度清为零,即该文件内容会消失。若文件不存在则建立该文件
“wb”只写打开或新建一个二进制文件;只允许写数据
“wb+”读写打开或建立一个二进制文件,允许读和写
“wt+”读写打开或着建立一个文本文件;允许读写
“a”以附加的方式打开只写文件。若文件不存在,则会建立该文件,如果文件存在,写入的数据会被加到文件尾,即文件原先的内容会被保留。(EOF符保留)
“a+”以附加方式打开可读写的文件。若文件不存在,则会建立该文件,如果文件存在,写入的数据会被加到文件尾后,即文件原先的内容会被保留。(原来的EOF符不保留)
“ab+”读写打开一个二进制文件,允许读或在文件末追加数据
“at+”读写打开一个文本文件,允许读或在文本末追加数据

返回值

  • 该函数返回一个 FILE 指针。否则返回 NULL,且设置全局变量 errno 来标识错误。

实例

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

int main()
{
   FILE * fp;

   fp = fopen ("file.txt", "w+");
   fprintf(fp, "%s %s %s %d", "We", "are", "in", 2014);
   
   fclose(fp);
   
   return(0);
}
让我们编译并运行上面的程序,这将创建一个带有一下内容的文件 file.txt:

We are in 2014
现在让我们使用下面的程序查看上面文件的内容:

#include <stdio.h>

int main ()
{
   FILE *fp;
   int c;
  
   fp = fopen("file.txt","r");
   while(1)
   {
      c = fgetc(fp);
      if( feof(fp) )
      { 
          break ;
      }
      printf("%c", c);
   }
   fclose(fp);
   return(0);
}
14.2.2 fclose() 函数关闭数据文件

描述

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

声明

int fclose(FILE *stream)

参数

  • stream – 这是指向 FILE 对象的指针,该 FILE 对象指定了要被关闭的流。

返回值

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

实例

#include <stdio.h>

int main()
{
   FILE *fp;
 
   fp = fopen("file.txt", "w");

   fprintf(fp, "%s", "这里是 runoob.com");
   fclose(fp);
   
   return(0);
}
让我们编译并运行上面的程序,这将创建一个文件 file.txt,然后写入下面的文本行,最后使用 fclose() 函数关闭文件。

这里是 runoob.com
14.3 顺序读写数据文件
14.3.1 fgetc() 函数说明

描述

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

声明

int fgetc(FILE *stream)

参数

  • stream – 这是指向 FILE 对象的指针,该 FILE 对象标识了要在上面执行操作的流。

返回值

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

实例

#include <stdio.h>

int main ()
{
   FILE *fp;
   int c;
   int n = 0;
  
   fp = fopen("file.txt","r");
   if(fp == NULL) 
   {
      perror("打开文件时发生错误");
      return(-1);
   }
   do
   {
      c = fgetc(fp);
      if( feof(fp) )
      {
          break ;
      }
      printf("%c", c);
   }while(1);

   fclose(fp);
   return(0);
}
假设我们有一个文本文件 file.txt,它的内容如下。文件将作为实例中的输入:

We are in 2014
让我们编译并运行上面的程序,这将产生以下结果:

We are in 2014
14.3.2 fputc() 函数说明

描述

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

声明

int fputs(const char *str, FILE *stream)

参数

  • str – 这是一个数组,包含了要写入的以空字符终止的字符序列。
  • stream – 这是指向 FILE 对象的指针,该 FILE 对象标识了要被写入字符串的流。

返回值

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

实例

#include <stdio.h>

int main ()
{
   FILE *fp;

   fp = fopen("file.txt", "w+");

   fputs("这是 C 语言。", fp);
   fputs("这是一种系统程序设计语言。", fp);

   fclose(fp);
   
   return(0);
}
让我们编译并运行上面的程序,这将创建文件 file.txt,它的内容如下:

这是 C 语言。这是一种系统程序设计语言。
现在让我们使用下面的程序查看上面文件的内容:

#include <stdio.h>

int main ()
{
   FILE *fp;
   int c;

   fp = fopen("file.txt","r");
   while(1)
   {
      c = fgetc(fp);
      if( feof(fp) )
      {
          break ;
      }
      printf("%c", c);
   }
   fclose(fp);
   return(0);
}
14.3.3 fgets() 函数说明

描述

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

声明

char *fgets(char *str, int n, FILE *stream)

参数

  • str – 这是指向一个字符数组的指针,该数组存储了要读取的字符串。
  • n – 这是要读取的最大字符数(包括最后的空字符)。通常是使用以 str 传递的数组长度。
  • stream – 这是指向 FILE 对象的指针,该 FILE 对象标识了要从中读取字符的流。

返回值

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

实例

#include <stdio.h>

int main()
{
   FILE *fp;
   char str[60];

   /* 打开用于读取的文件 */
   fp = fopen("file.txt" , "r");
   if(fp == NULL) {
      perror("打开文件时发生错误");
      return(-1);
   }
   if( fgets (str, 60, fp)!=NULL ) {
      /* 向标准输出 stdout 写入内容 */
      puts(str);
   }
   fclose(fp);
   
   return(0);
}
假设我们有一个文本文件 file.txt,它的内容如下。文件将作为实例中的输入:

We are in 2014
让我们编译并运行上面的程序,这将产生以下结果:

We are in 2014
14.3.4 fprintf() 函数说明

描述

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

声明

int fprintf(FILE *stream, const char *format, ...)

参数

  • stream – 这是指向 FILE 对象的指针,该 FILE 对象标识了流。
  • format – 这是 C 字符串,包含了要被写入到流 stream 中的文本。它可以包含嵌入的 format 标签,format 标签可被随后的附加参数中指定的值替换,并按需求进行格式化。format 标签属性是 %[flags][width][.precision][length]specifier,具体如下

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
返回值

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

实例

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

int main()
{
   FILE * fp;

   fp = fopen ("file.txt", "w+");
   fprintf(fp, "%s %s %s %d", "We", "are", "in", 2014);
   
   fclose(fp);
   
   return(0);
}
让我们编译并运行上面的程序,这将创建文件 file.txt,它的内容如下:

We are in 2014
现在让我们使用下面的程序查看上面文件的内容:

#include <stdio.h>

int main ()
{
   FILE *fp;
   int c;

   fp = fopen("file.txt","r");
   while(1)
   {
      c = fgetc(fp);
      if( feof(fp) )
      {
          break ;
      }
      printf("%c", c);
   }
   fclose(fp);
   return(0);
}
14.3.5 fscanf() 函数说明

描述

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

声明

int fscanf(FILE *stream, const char *format, ...)

参数

  • stream – 这是指向 FILE 对象的指针,该 FILE 对象标识了流。
  • format – 这是 C 字符串,包含了以下各项中的一个或多个:空格字符、非空格字符 和 format 说明符。
    format 说明符形式为 [=%[*][width][modifiers]type=],具体如下
    在这里插入图片描述
    返回值
  • 如果成功,该函数返回成功匹配和赋值的个数。如果到达文件末尾或发生读错误,则返回 EOF。

实例

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


int main()
{
   char str1[10], str2[10], str3[10];
   int year;
   FILE * fp;

   fp = fopen ("file.txt", "w+");
   fputs("We are in 2014", fp);
   
   rewind(fp);
   fscanf(fp, "%s %s %s %d", str1, str2, str3, &year);
   
   printf("Read String1 |%s|\n", str1 );
   printf("Read String2 |%s|\n", str2 );
   printf("Read String3 |%s|\n", str3 );
   printf("Read Integer |%d|\n", year );

   fclose(fp);
   
   return(0);
}
让我们编译并运行上面的程序,这将产生以下结果:

Read String1 |We|
Read String2 |are|
Read String3 |in|
Read Integer |2014|
14.3.6 fread() 函数说明

描述

C 库函数 size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream) 从给定流 stream 读取数据到 ptr 所指向的数组中。

声明

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

参数

  • ptr – 这是指向带有最小尺寸 size*nmemb 字节的内存块的指针。
  • size – 这是要读取的每个元素的大小,以字节为单位。
  • nmemb – 这是元素的个数,每个元素的大小为 size 字节。
  • stream – 这是指向 FILE 对象的指针,该 FILE 对象指定了一个输入流。

返回值

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

实例

#include <stdio.h>
#include <string.h>
 
int main()
{
   FILE *fp;
   char c[] = "This is runoob";
   char buffer[20];
 
   /* 打开文件用于读写 */
   fp = fopen("file.txt", "w+");
 
   /* 写入数据到文件 */
   fwrite(c, strlen(c) + 1, 1, fp);
 
   /* 查找文件的开头 */
   fseek(fp, 0, SEEK_SET);
 
   /* 读取并显示数据 */
   fread(buffer, strlen(c)+1, 1, fp);
   printf("%s\n", buffer);
   fclose(fp);
   
   return(0);
}
让我们编译并运行上面的程序,这将创建一个文件 file.txt,然后写入内容 This is runoob。接下来我们使用 fseek() 函数来重置写指针到文件的开头,文件内容如下所示:

This is runoob
14.3.7 fwrite() 函数说明

描述

C 库函数 size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream) 把 ptr 所指向的数组中的数据写入到给定流 stream 中。

声明

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

参数

  • ptr – 这是指向要被写入的元素数组的指针。
  • size – 这是要被写入的每个元素的大小,以字节为单位。
  • nmemb – 这是元素的个数,每个元素的大小为 size 字节。
  • stream – 这是指向 FILE 对象的指针,该 FILE 对象指定了一个输出流。

返回值

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

实例

#include<stdio.h>
 
int main ()
{
   FILE *fp;
   char str[] = "This is runoob.com";
 
   fp = fopen( "file.txt" , "w" );
   fwrite(str, sizeof(str) , 1, fp );
 
   fclose(fp);
  
   return(0);
}
让我们编译并运行上面的程序,这将创建一个文件 file.txt,它的内容如下:

This is runoob.com
现在让我们使用下面的程序查看上面文件的内容:

实例
#include <stdio.h>
 
int main ()
{
   FILE *fp;
   int c;
 
   fp = fopen("file.txt","r");
   while(1)
   {
      c = fgetc(fp);
      if( feof(fp) )
      {
          break ;
      }
      printf("%c", c);
   }
   fclose(fp);
   return(0);
}
14.4 随机读写数据文件
14.4.1 rewind() 函数

描述

C 库函数 void rewind(FILE *stream) 设置文件位置为给定流 stream 的文件的开头。

声明

void rewind(FILE *stream)

参数

  • stream – 这是指向 FILE 对象的指针,该 FILE 对象标识了流。

返回值

  • 该函数不返回任何值。

实例

#include <stdio.h>

int main()
{
   char str[] = "This is runoob.com";
   FILE *fp;
   int ch;

   /* 首先让我们在文件中写入一些内容 */
   fp = fopen( "file.txt" , "w" );
   fwrite(str , 1 , sizeof(str) , fp );
   fclose(fp);

   fp = fopen( "file.txt" , "r" );
   while(1)
   {
      ch = fgetc(fp);
      if( feof(fp) )
      {
          break ;
      }
      printf("%c", ch);
   }
   rewind(fp);
   printf("\n");
   while(1)
   {
      ch = fgetc(fp);
      if( feof(fp) )
      {
          break ;
      }
      printf("%c", ch);
     
   }
   fclose(fp);

   return(0);
}
假设我们有一个文本文件 file.txt,它的内容如下:

This is runoob.com
让我们编译并运行上面的程序,这将产生以下结果:

This is runoob.com
This is runoob.com
14.4.2 fseek() 函数

描述

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

声明

int fseek(FILE *stream, long int offset, int whence)

参数

  • stream – 这是指向 FILE 对象的指针,该 FILE 对象标识了流。
  • offset – 这是相对 whence 的偏移量,以字节为单位。
  • whence – 这是表示开始添加偏移 offset 的位置。它一般指定为下列常量之一:
常量描述
SEEK_SET文件的开头
SEEK_CUR文件指针的当前位置
SEEK_END文件的末尾

返回值

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

实例

下面的实例演示了 fseek() 函数的用法。

#include <stdio.h>

int main ()
{
   FILE *fp;

   fp = fopen("file.txt","w+");
   fputs("This is runoob.com", fp);
  
   fseek( fp, 7, SEEK_SET );
   fputs(" C Programming Langauge", fp);
   fclose(fp);
   
   return(0);
}
让我们编译并运行上面的程序,这将创建文件 file.txt,它的内容如下。最初程序创建文件和写入 This is runoob.com,但是之后我们在第七个位置重置了写指针,并使用 puts() 语句来重写文件,内容如下:

This is C Programming Langauge
现在让我们使用下面的程序查看上面文件的内容:

#include <stdio.h>

int main ()
{
   FILE *fp;
   int c;

   fp = fopen("file.txt","r");
   while(1)
   {
      c = fgetc(fp);
      if( feof(fp) )
      {
          break ;
      }
      printf("%c", c);
   }
   fclose(fp);
   return(0);
}
14.4.3 ftell() 函数
C 库函数 long int ftell(FILE *stream) 返回给定流 stream 的当前文件位置。

声明

long int ftell(FILE *stream)

参数

  • stream – 这是指向 FILE 对象的指针,该 FILE 对象标识了流。

返回值

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

实例

#include <stdio.h>

int main ()
{
   FILE *fp;
   int len;

   fp = fopen("file.txt", "r");
   if( fp == NULL ) 
   {
      perror ("打开文件错误");
      return(-1);
   }
   fseek(fp, 0, SEEK_END);

   len = ftell(fp);
   fclose(fp);

   printf("file.txt 的总大小 = %d 字节\n", len);
   
   return(0);
}
假设我们有一个文本文件 file.txt,它的内容如下:

This is runoob.com
让我们编译并运行上面的程序,如果文件内容如上所示,这将产生以下结果,否则会根据文件内容给出不同的结果:

file.txt 的总大小 = 19 字节
14.5 文件读写的出错检测
14.5.1 ferror函数

描述

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

声明

int ferror(FILE *stream)

参数

  • stream – 这是指向FILE对象的指针,该FILE对象标识了流。

返回值

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

实例

下面的实例演示了 ferror() 函数的用法。

#include <stdio.h>

int main()
{
   FILE *fp;
   char c;

   fp = fopen("file.txt", "w");

   c = fgetc(fp);
   if( ferror(fp) )
   {
      printf("读取文件:file.txt 时发生错误\n");
   }
   clearerr(fp);
   if( ferror(fp) )
   {
      printf("读取文件:file.txt 时发生错误\n");
   }
   fclose(fp);

   return(0);
}
假设我们有一个文本文件 file.txt,它是一个空文件。让我们编译并运行上面的程序,因为我们试图读取一个以只写模式打开的文件,这将产生以下结果。

读取文件:file.txt 时发生错误
14.5.2 clearerr函数

描述

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

声明

void clearerr(FILE *stream)

参数

  • stream – 这是指向 FILE 对象的指针,该 FILE 对象标识了流。

返回值

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

实例

下面的实例演示了 clearerr() 函数的用法。

#include <stdio.h>

int main()
{
   FILE *fp;
   char c;

   fp = fopen("file.txt", "w");

   c = fgetc(fp);
   if( ferror(fp) )
   {
      printf("读取文件:file.txt 时发生错误\n");
   }
   clearerr(fp);
   if( ferror(fp) )
   {
      printf("读取文件:file.txt 时发生错误\n");
   }
   fclose(fp);

   return(0);
}
假设我们有一个文本文件 file.txt,它是一个空文件。让我们编译并运行上面的程序,因为我们试图读取一个以只写模式打开的文件,这将产生以下结果。

读取文件:file.txt 时发生错误
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值