【《C Primer Plus》读书笔记】第13章:文件输入/输出

13.1 与文件进行通信

13.1.1 文件是什么

文件通常是在磁盘或固态硬盘上的一段已命名的存储区。

C把文件看作是一系列连续的字节,每个字节都能被单独读取。

C提供两种文件模式:文本模式二进制模式

13.1.2 文本模式和二进制模式

所有文件的内容(在磁盘上)都以二进制(0或1)表示。

因为编码方式不同,导致展现的形式不同。

定义

  • 如果文件使用二进制编码的字符,如Unicode,ASCII表示文本,那么就是文本文件。
  • 如果二进制代表的是机器语言,或数值数据,或图片,或音乐编码,该文件就是二进制文件。

区别

  1. 对于字符串中\n的处理不同。
    在Windows系统中用文本模式打开文件时会发现文件中的换行符是\n,这看起来再正常不过了,但当你改为用二进制模式打开文件时会发现文件中的换行符变为\r\n
    事实上,在Windows系统中的的文件中的换行符都是\r\n,只不过在使用文本模式时,会把文件内容从文本的系统表示法映射为C表示法,而使用二进制表示法时不会进行映射转换。

  2. 以二进制模式打开文件是,可以逐字节读取文件。
    这也就是为什么在使用部分函数例如fseek()和ftell()时必须以二进制模式打开文件

  3. 使用文本模式打开文件时,就要用fprintf()写入数据,使用二进制模式打开文件时候,就要用fwrite()写入数据。
    这是因为fprintf()类型的函数会将数据转换为文本,而fwrite()这类函数则不会。

为了规范文本文件的处理,C提供两种访问文件的途径:文本模式二进制模式

  • 在二进制模式中,程序可以访问文件的每个字节。
  • 在文本模式中,程序所见的内容与文件实际内容不同。典型代表就是对于字符串中\n的处理。

13.1.3 I/O的级别

  • 底层I/O:使用操作系统的基本I/O服务。
  • 标准高级I/O:使用C库的标准包和stdio.h头文件定义。

C标准只支持标准I/O包。有些实现会提供底层库,但C标准建立了可移植的I/O模型。

13.1.4 标准文件

C程序会自动打开3个文件:标准输入、标准输出、标准错误输出。

标准输入是系统的普通输入设备,通常是键盘。

标准输出、标准错误输出是系统的普通输出设备,通常是显示屏。

标准错误输出提供了一个从逻辑上不同的地方来发送错误的信息。

13.2 标准I/O

标准I/O由ANSI C标准定义,C标准中定义了C库,标准I/O就是C库中用来输入和输出的函数。标准I/O在系统调用的上一层多加了一个缓冲区,通过缓冲机制减少了系统调用,实现更高的效率。

标准I/O包的3个好处:

  1. 可移植
  2. 标准I/O有许多专门的函数简化了处理不同I/O的问题
  3. 输入和输出都是缓冲

程序清单13.1 count.c程序

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

int main(int argc, char *argv[])
{
    int ch;
    FILE *fp;
    unsigned count = 0;
    if (argc != 2)
    {
        printf("Usage: %s filename\n", argv[0]);
        exit(EXIT_FAILURE);
    }
    if ((fp = fopen(argv[1], "r")) == NULL)
    {
        printf("Can't open %s\n", argv[1]);
        exit(EXIT_FAILURE);
    }
    while ((ch = getc(fp)) != EOF)
    {
        putc(ch, stdout);
        count++;
    }
    fclose(fp);
    printf("File %s has %lu characters\n", argv[1], count);

    system("pause");
    return 0;
}

13.3 一个简单的文件压缩程序

程序清单13.2 reducto.c程序

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define LEN 40

int main(int argc, char *argv[])
{
    FILE *in, *out;
    int ch;
    char name[LEN];
    int count = 0;

    if (argc < 2)
    {
        fprintf(stderr, "Usage: %s filename\n", argv[0]);
        exit(EXIT_FAILURE);
    }
    if ((in = fopen(argv[1], "r")) == NULL)
    {
        fprintf(stderr, "I couldn't open the file \"%s\"\n", argv[1]);
        exit(EXIT_FAILURE);
    }
    strncpy(name, argv[1], LEN - 5);
    name[LEN - 5] = '\0';
    strcat(name, ".red");
    if ((out = fopen(name, "w")) == NULL)
    {
        fprintf(stderr, "Can't create output file.\n");
        exit(3);
    }
    while ((ch = getc(in)) != EOF)
        if (count++ % 3 == 0)
            putc(ch, out);
    if (fclose(in) != 0 || fclose(out) != 0)
        fprintf(stderr, "Error in closing files\n");
    
    system("pause");
    return 0;
}

运行结果:

在这里插入图片描述

在这里插入图片描述

13.4 文件I/O:fprintf()、fscanf()、fgets()和fputs()

程序清单13.3 addword.c程序

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 41

int main(void)
{
    FILE *fp;
    char words[MAX];

    if ((fp = fopen("wordy", "a+")) == NULL)
    {
        fprintf(stderr, "Can't open \"wordy\" file.\n");
        exit(EXIT_FAILURE);
    }

    puts("Enter words to add to the file; press the #");
    puts("key at the beginning of a line to terminate.");
    while ((fscanf(stdin, "%40s", words) == 1) && (words[0] != '#'))
        fprintf(fp, "%s\n", words);
    
    puts("File contents:");
    rewind(fp); /*返回到文件开始处*/
    while (fscanf(fp, "%s", words) == 1)
        puts(words);
    puts("Done!");
    if (fclose(fp) != 0)
        fprintf(stderr, "Error closing file\n");
    
    system("pause");
    return 0;
}

运行结果:

在这里插入图片描述

在这里插入图片描述

13.5 随机访问:fseek()和ftell()

C 库函数 - fseek()

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

声明
下面是 fseek() 函数的声明。

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);
}

运行结果:

在这里插入图片描述

C 库函数 - ftell()

描述
C 库函数 long int ftell(FILE *stream) 返回给定流 stream 的当前文件位置,即:参数指向文件的当前位置距文件开始处的字节数。

声明:
下面是 ftell() 函数的声明。

long int ftell(FILE *stream)

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

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

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

#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 的总大小 = 18 字节

运行结果:

This is runoob.com

reverse.c

程序清单13.4 reverse.c

逆序打印文件内容。

代码:

#include <stdio.h>
#include <stdlib.h>
#define CNTL_Z '\032' /* eof marker in DOS text files */
#define SLEN 81
int main(void)
{
    char file[SLEN];
    char ch;
    FILE *fp;
    long count, last;

    puts("Enter the name of the file to be processed:");
    scanf("%80s", file);
    if ((fp = fopen(file, "rb")) == NULL)
    { /* read-only mode   */
        printf("reverse can't open %s\n", file);
        exit(EXIT_FAILURE);
    }

    fseek(fp, 0L, SEEK_END); /* go to end of file */
    last = ftell(fp);
    for (count = 1L; count <= last; count++)
    {
        fseek(fp, -count, SEEK_END); /* go backward      */
        ch = getc(fp);
        if (ch != CNTL_Z && ch != '\r') /* MS-DOS files */
            putchar(ch);
    }
    putchar('\n');
    fclose(fp);

    return 0;
}

文件内容:

在这里插入图片描述

运行结果:

在这里插入图片描述

13.5.2 二进制模式和文本模式

ftell()函数在二进制模式和文本模式的工作方式不同。

ANSI C规定:

  • 对于文本模式,ftell()返回的值可以作为fseek()的第2个参数。
  • 对于MS-DOS,ftell()返回的值把\r\n当作一个字节计数。

13.5.3 可移植性

理论上,fseek()和ftell()应该符合UNIX模型。

限制:

  • 在二进制模式中,实现不必支持SEEK_END模式
  • 在文本模式中,只有以下调用能保证其相应的行为
函数调用效果
fseek(file, 0L, SEEK_SET)定位到文件的开头
fseek(file, 0L, SEEK_CUR)保持当前位置不动
fseek(file, 0L, SEEK_END)定位到文件的末尾
fseek(file, ftell_pos, SEEK_SET)到距离文件开始处ftell_pos的位置,ftell_pos是ftell()的返回值

不过,许多常见的环境都支持更多的行为。

13.5.4 fgetpos()和fsetpos()函数

fseek()和ftell()潜在的问题是,它们都把文件大小限制在long类型能表达的范围内。

但随着文件越来越大,ANSI C新增了2个处理较大文件的新定位函数:fgetpos()fsetpos()

这两个函数不使用long类型的值表示位置,它们使用一种全新的类型:fpos_t

C 库函数 - fgetpos()

描述
C 库函数 int fgetpos(FILE *stream, fpos_t *pos) 获取流 stream 的当前文件位置,并把它写入到 pos。

声明
下面是 fgetpos() 函数的声明。

int fgetpos(FILE *stream, fpos_t *pos)

参数
stream – 这是指向 FILE 对象的指针,该 FILE 对象标识了流。
pos – 这是指向 fpos_t 对象的指针。

返回值
如果成功,该函数返回零。如果发生错误,则返回非零值。

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

#include <stdio.h>

int main ()
{
   FILE *fp;
   fpos_t position;

   fp = fopen("file.txt","w+");
   fgetpos(fp, &position);
   fputs("Hello, World!", fp);
  
   fsetpos(fp, &position);
   fputs("这将覆盖之前的内容", fp);
   fclose(fp);
   
   return(0);
}

让我们编译并运行上面的程序,这将创建一个文件 file.txt,它的内容如下。首先我们使用 fgetpos() 函数获取文件的初始位置,接着我们向文件写入 Hello, World!,然后我们使用 fsetpos() 函数来重置写指针到文件的开头,重写文件为下列内容:

这将覆盖之前的内容

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

#include <stdio.h>

int main ()
{
   FILE *fp;
   int c;
   int n = 0;

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

   fclose(fp);

   return(0);
}

运行结果:

在这里插入图片描述

执行第13行代码前,file.txt的内容:

在这里插入图片描述

执行第13行代码前,覆盖后file.txt的内容:

在这里插入图片描述

13.6 标准I/O的机理

通常,使用标准I/O的第1步是调用fopen()打开文件(前面介绍过,C程序会自动打开3种标准文件)。fopen()函数不仅打开一个文件,还创建了一个缓冲区(在读写模式下会创建两个缓冲区)以及一个包含文件和缓冲区数据的结构。另外,fopen()返回一个指向该结构的指针,以便其他函数知道如何找到该结构。假设把该指针赋给一个指针变量fp,我们说fopen()函数“打开一个流”。如果以文本模式打开该文件,就获得一个文本流;如果以二进制模式打开该文件,就获得一个二进制流。

这个结构通常包含一个指定流中当前位置的文件位置指示器。除此之外,它还包含错误和文件结尾的指示器、一个指向缓冲区开始处的指针、一个文件标识符和一个计数(统计实际拷贝进缓冲区的字节数)。

我们主要考虑文件输入。通常,使用标准I/O的第2步是调用一个定义在stdio.h中的输入函数,如fscanf()、getc()或 fgets()。一调用这些函数,文件中的数据块就被拷贝到缓冲区中。缓冲区的大小因实现而异,一般是512字节或是它的倍数,如4096或16384(随着计算机硬盘容量越来越大,缓冲区的大小也越来越大)。最初调用函数,除了填充缓冲区外,还要设置fp所指向的结构中的值。尤其要设置流中的当前位置和拷贝进缓冲区的字节数。通常,当前位置从字节0开始。

在初始化结构和缓冲区后,输入函数按要求从缓冲区中读取数据。在它读取数据时,文件位置指示器被设置为指向刚读取字符的下一个字符。由于stdio.h系列的所有输入函数都使用相同的缓冲区,所以调用任何一个函数都将从上一次函数停止调用的位置开始。

当输入函数发现已读完缓冲区中的所有字符时,会请求把下一个缓冲大小的数据块从文件拷贝到该缓冲区中。以这种方式,输入函数可以读取文件中的所有内容,直到文件结尾。函数在读取缓冲区中的最后一个字符后,把结尾指示器设置为真。于是,下一次被调用的输入函数将返回EOF。

输出函数以类似的方式把数据写入缓冲区。当缓冲区被填满时,数据将被拷贝至文件中。

13.7 其他标准I/O函数

C 库函数 - ungetc()

描述
C 库函数 int ungetc(int char, FILE *stream) 把字符 char(一个无符号字符)推入到指定的流 stream 中,以便它是下一个被读取到的字符。

声明
下面是 ungetc() 函数的声明。

int ungetc(int char, FILE *stream)

参数
char – 这是要被推入的字符。该字符以其对应的 int 值进行传递。
stream – 这是指向 FILE 对象的指针,该 FILE 对象标识了输入流。

返回值
如果成功,则返回被推入的字符,否则返回 EOF,且流 stream 保持不变。

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

代码:

#include <stdio.h>

int main ()
{
   FILE *fp;
   int c;
   char buffer [256];

   fp = fopen("file.txt", "r");
   if( fp == NULL )
   {
      perror("打开文件时发生错误");
      return(-1);
   }
   while(!feof(fp))
   {
      c = getc (fp);
      /* 把 ! 替换为 + */
      if( c == '!' )
      {
         ungetc ('+', fp);
      }
      else
      {
         ungetc(c, fp);
      }
      fgets(buffer, 255, fp);
      fputs(buffer, stdout);
   }
   return(0);
}

假设我们有一个文本文件 file.txt,它的内容如下。文件将作为实例中的输入:

this is runoob
!c standard library
!library functions and macros

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

this is runoob
+c standard library
+library functions and macros

运行结果:

在这里插入图片描述

输出:

在这里插入图片描述

C 库函数 - fflush()

描述
C 库函数 int fflush(FILE *stream) 刷新流 stream 的输出缓冲区。

声明
下面是 fflush() 函数的声明。

int fflush(FILE *stream)

参数
stream – 这是指向 FILE 对象的指针,该 FILE 对象指定了一个缓冲流。
返回值
如果成功,该函数返回零值。如果发生错误,则返回 EOF,且设置错误标识符(即 feof)。

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

代码:

#include <stdio.h>
#include <string.h>
 
int main()
{
 
   char buff[1024];
 
   memset( buff, '\0', sizeof( buff ));
 
   fprintf(stdout, "启用全缓冲\n");
   setvbuf(stdout, buff, _IOFBF, 1024);
 
   fprintf(stdout, "这里是 runoob.com\n");
   fprintf(stdout, "该输出将保存到 buff\n");
   fflush( stdout );
 
   fprintf(stdout, "这将在编程时出现\n");
   fprintf(stdout, "最后休眠五秒钟\n");
 
   sleep(5);
 
   return(0);
}

让我们编译并运行上面的程序,这将产生以下结果。在这里,程序把缓冲输出保存到 buff,直到首次调用 fflush() 为止,然后开始缓冲输出,最后休眠 5 秒钟。它会在程序结束之前,发送剩余的输出到 STDOUT。

启用全缓冲
这里是 runoob.com
该输出将保存到 buff
这将在编程时出现
最后休眠五秒钟

说明

调用fflush()函数引起输出缓冲区中所有的未写入数据被发送到参数fp指定的输出文件。

这个过程称为刷新缓冲区

如果fp是空指针, 所有输出缓冲区都被刷新。

在输入流中使用fflush()函数的效果是未定义的。只要最近一次操作不是输入操作,就可以用该函数来更新流。

运行结果:

在这里插入图片描述

C 库函数 - setvbuf()

描述
C 库函数 int setvbuf(FILE *stream, char *buffer, int mode, size_t size) 定义流 stream 应如何缓冲。

声明
下面是 setvbuf() 函数的声明。

int setvbuf(FILE *stream, char *buffer, int mode, size_t size)

参数

  • stream – 这是指向 FILE 对象的指针,该 FILE 对象标识了一个打开的流。
  • buffer – 这是分配给用户的缓冲。如果设置为 NULL,该函数会自动分配一个指定大小的缓冲。
  • mode – 这指定了文件缓冲的模式:
模式描述
_IOFBF全缓冲:对于输出,数据在缓冲填满时被一次性写入。对于输入,缓冲会在请求输入且缓冲为空时被填充。
_IOLBF行缓冲:对于输出,数据在遇到换行符或者在缓冲填满时被写入,具体视情况而定。对于输入,缓冲会在请求输入且缓冲为空时被填充,直到遇到下一个换行符。
_IONBF无缓冲:不使用缓冲。每个 I/O 操作都被即时写入。buffer 和 size 参数被忽略。
  • size --这是缓冲的大小,以字节为单位。

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

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

代码:

#include <stdio.h>
#include <unistd.h>
#include <string.h>
int main()
{
 
   char buff[1024];
 
   memset( buff, '\0', sizeof( buff ));
 
   fprintf(stdout, "启用全缓冲\n");
   setvbuf(stdout, buff, _IOFBF, 1024);
 
   fprintf(stdout, "这里是 runoob.com\n");
   fprintf(stdout, "该输出将保存到 buff\n");
   fflush( stdout );
 
   fprintf(stdout, "这将在编程时出现\n");
   fprintf(stdout, "最后休眠五秒钟\n");
 
   sleep(5);
 
   return(0);
}

让我们编译并运行上面的程序,这将产生以下结果。在这里,程序把缓冲输出保存到 buff,直到首次调用 fflush() 为止,然后开始缓冲输出,最后休眠 5 秒钟。它会在程序结束之前,发送剩余的输出到 STDOUT。

启用全缓冲
这里是 runoob.com
该输出将保存到 buff
这将在编程时出现
最后休眠五秒钟

运行结果:

在这里插入图片描述

C 库函数 - fread()和fwrite()

对于标准I/O,fread()和fwrite()函数用于以二进制行式处理数据。

fread()

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

声明
下面是 fread() 函数的声明。

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 参数不同,则可能发生了一个错误或者到达了文件末尾。

fwrite()

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

声明
下面是 fwrite() 函数的声明。

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>
#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

运行结果:

在这里插入图片描述

C 库函数 - feof()

描述
C 库函数 int feof(FILE *stream) 测试给定流 stream 的文件结束标识符。

声明
下面是 feof() 函数的声明。

int feof(FILE *stream)

参数

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

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

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

#include <stdio.h>

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

假设我们有一个文本文件 file.txt,它的内容如下所示。该文件将作为我们实例程序中的一个输入使用:

这里是 runoob.com

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

这里是 runoob.com

运行结果:

在这里插入图片描述

C 库函数 - ferror()

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

声明
下面是 ferror() 函数的声明。

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 时发生错误
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

UestcXiye

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值