C语言从入门到实战——文件操作

news2024/11/13 15:27:15

文件操作

  • 前言
  • 一、 为什么使用文件
  • 二、 什么是文件
    • 2.1 程序文件
    • 2.2 数据文件
    • 2.3 文件名
  • 三、 二进制文件和文本文件
  • 四、 文件的打开和关闭
    • 4.1 流和标准流
      • 4.1.1 流
      • 4.1.2 标准流
    • 4.2 文件指针
    • 4.3 文件的打开和关闭
    • 4.4 文件的路径
  • 五、 文件的顺序读写
    • 5.1 顺序读写函数介绍
      • fgetc
      • fputc
      • fgets
      • fputs
      • fscanf
      • fprintf
      • fread
      • fwrite
    • 5.2 对比一组函数
      • sscanf
      • sprintf
    • 5.3标准的数据拷贝
  • 六、 文件的随机读写
    • 6.1 fseek
    • 6.2 ftell
    • 6.3 rewind
  • 七、 文件读取结束的判定
    • fgetc
    • fgets
    • 7.1 被错误使用的 feof
  • 八、 文件缓冲区


前言

C语言中的文件操作是通过使用文件指针来实现的。可以使用标准库中的函数来打开、读取、写入和关闭文件。

下面是一些常见的文件操作函数:

  1. 打开文件:使用 fopen() 函数来打开文件,该函数接受两个参数,文件名和打开方式。打开方式可以是 "r"(只读模式),"w"(写入模式),"a"(追加模式)等等。函数返回一个文件指针,可以在后续的操作中使用。
FILE *fp;
fp = fopen("filename.txt", "r");
  1. 读取文件内容:使用 fscanf() 函数来从文件中读取内容。该函数接受一个文件指针和一个格式字符串作为参数,读取文件中的数据并按照格式字符串的指示将数据存储到相应的变量中。
int num;
fscanf(fp, "%d", &num);
  1. 写入文件内容:使用 fprintf() 函数来向文件中写入内容。该函数接受一个文件指针和一个格式字符串作为参数,将相应的数据按照格式字符串的指示写入文件。
int num = 10;
fprintf(fp, "%d", num);
  1. 关闭文件:使用 fclose() 函数来关闭文件,该函数接受一个文件指针作为参数。
fclose(fp);

在进行文件操作时,需要注意以下几点:

  • 在打开文件之前要确保文件存在,或者在打开文件时使用合适的打开方式。
  • 在读取和写入文件时要确保文件指针指向正确的位置,可以使用 fseek() 函数来调整文件指针的位置。
  • 每次读取或写入文件后,都要检查函数的返回值,以确保文件操作成功。
  • 在完成文件操作后,一定要关闭文件,释放文件指针所占用的资源。

这是一个简单的文件操作的示例:

#include <stdio.h>

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

    // 打开文件
    fp = fopen("numbers.txt", "r");
    if (fp == NULL) {
        printf("无法打开文件\n");
        return 1;
    }

    // 读取文件内容
    fscanf(fp, "%d", &num);
    printf("文件中的数字是:%d\n", num);

    // 关闭文件
    fclose(fp);

    return 0;
}

在上面的示例中,程序打开了一个名为 numbers.txt 的文件,读取文件中的一个整数,并打印出来。最后关闭了文件。


一、 为什么使用文件

如果没有文件,我们写的程序的数据是存储在电脑的内存中,如果程序退出,内存回收,数据就丢失了,等再次运行程序,是看不到上次程序的数据的,如果要将数据进行持久化的保存,我们可以使用文件。

二、 什么是文件

在这里插入图片描述
磁盘上的文件是文件。

但是在程序设计中,我们一般谈的文件有两种:程序文件、数据文件(从文件功能的角度来分类的)。

文件的本质是结构体

2.1 程序文件

程序文件包括源程序文件(后缀为.c),目标文件(windows环境后缀为.obj),可执行程序(windows环境后缀为.exe)。

2.2 数据文件

文件的内容不一定是程序,而是程序运行时读写的数据,比如程序运行需要从中读取数据的文件,或者输出内容的文件。

在以前文章中所处理数据的输入输出都是以终端为对象的,即从终端的键盘输入数据,运行结果显示到显示器上。

其实有时候我们会把信息输出到磁盘上,当需要的时候再从磁盘上把数据读取到内存中使用,这里处理的就是磁盘上文件。

2.3 文件名

一个文件要有一个唯一的文件标识,以便用户识别和引用。

文件名包含3部分:文件路径+文件名主干+文件后缀

例如: c:\code\test.txt

为了方便起见,文件标识常被称为文件名。

三、 二进制文件和文本文件

根据数据的组织形式,数据文件被称为文本文件或者二进制文件。

数据在内存中以二进制的形式存储,如果不加转换的输出到外存,就是二进制文件。

如果要求在外存上以ASCII码的形式存储,则需要在存储前转换。以ASCII字符的形式存储的文件就是文本文件。

一个数据在内存中是怎么存储的呢?

字符一律以ASCII形式存储,数值型数据既可以用ASCII形式存储,也可以使用二进制形式存储。如有整数10000,如果以ASCII码的形式输出到磁盘,则磁盘中占用5个字节(每个字符一个字节),而二进制形式输出,则在磁盘上只占4个字节(VS2019测试)。
在这里插入图片描述

#include <stdio.h>
int main()
{
	int a = 10000;
	FILE* pf = fopen("test.txt", "wb");
	fwrite(&a, 4, 1, pf); //二进制的形式写到文件中
	fclose(pf);
	pf = NULL;
	return 0;
}

在VS上打开二进制文件:
在这里插入图片描述
在这里插入图片描述

四、 文件的打开和关闭

4.1 流和标准流

4.1.1 流

我们程序的数据需要输出到各种外部设备,也需要从外部设备获取数据,不同的外部设备的输入输出操作各不相同,为了方便程序员对各种设备进行方便的操作,我们抽象出了流的概念,我们可以把流想象成流淌着字符的河。

C程序针对文件、画面、键盘等的数据输入输出操作都是通过流操作的。

一般情况下,我们要想向流里写数据,或者从流中读取数据,都是要打开流,然后操作。

4.1.2 标准流

那为什么我们从键盘输入数据,向屏幕上输出数据,并没有打开流呢?

标准输入输出流是默认打开的,可以直接使用

那是因为C语言程序在启动的时候,默认打开了3个流:

  • stdin-标准输入流,在大多数的环境中从键盘输入,scanf函数就是从标准输入流中读取数据。
  • stdout-标准输出流,大多数的环境中输出至显示器界面,printf函数就是将信息输出到标准输出流中。
  • stderr-标准错误流,大多数环境中输出到显示器界面。

这是默认打开了这三个流,我们使用scanfprintf等函数就可以直接进行输入输出操作的。

stdinstdoutstderr三个流的类型是: FILE* ,通常称为文件指针。

C语言中,就是通过 FILE* 的文件指针来维护流的各种操作的。

4.2 文件指针

缓冲文件系统中,关键的概念是“文件类型指针”,简称“文件指针”。

每个被使用的文件都在内存中开辟了一个相应的文件信息区,用来存放文件的相关信息(如文件的名字,文件状态及文件当前的位置等)。这些信息是保存在一个结构体变量中的。该结构体类型是由系统声明的,取名FILE.

例如,VS2013编译环境提供的 stdio.h 头文件中有以下的文件类型申明:

struct _iobuf {
	char *_ptr;
	int _cnt;
	char *_base;
	int _flag;
	int _file;
	int _charbuf;
	int _bufsiz;
	char *_tmpfname;
};
typedef struct _iobuf FILE;

不同的C编译器的FILE类型包含的内容不完全相同,但是大同小异。

每当打开一个文件的时候,系统会根据文件的情况自动创建一个FILE结构的变量,并填充其中的信息,使用者不必关心细节。

一般都是通过一个FILE的指针来维护这个FILE结构的变量,这样使用起来更加方便。

下面我们可以创建一个FILE*的指针变量:

FILE* pf; //文件指针变量

定义pf是一个指向FILE类型数据的指针变量。可以使pf指向某个文件的文件信息区(是一个结构体变量)。通过该文件信息区中的信息就能够访问该文件。也就是说,通过文件指针变量能够间接找到与它关联的文件。

比如:

在这里插入图片描述
创建文件变量,data的数据会拷贝到f 这个文件结构体中,将这个文件结构体填满
在这里插入图片描述

4.3 文件的打开和关闭

文件操作,操作成功返回文件指针,操作失败会返回NULL

文件在读写之前应该先打开文件,在使用结束之后应该关闭文件。

在编写程序的时候,在打开文件的同时,都会返回一个FILE*的指针变量指向该文件,也相当于建立了指针和文件的关系。

ANSIC 规定使用 fopen 函数来打开文件,fclose 来关闭文件。

//打开文件
FILE * fopen ( const char * filename, const char * mode );
//关闭文件
int fclose ( FILE * stream );

mode表示文件的打开模式,下面都是文件的打开模式:

文件使用方式含义如果指定文件不存在
r”(只读)为了输入数据,打开一个已经存在的文本文件出错
w”(只写)为了输出数据,打开一个文本文件建立一个新的文件
a”(追加)向文本文件尾添加数据建立一个新的文件
rb”(只读)为了输入数据,打开一个二进制文件出错
wb”(只写)为了输出数据,打开一个二进制文件建立一个新的文件
ab”(追加)向一个二进制文件尾添加数据建立一个新的文件
r+”(读写)为了读和写,打开一个文本文件出错
w+”(读写)为了读和写,建议一个新的文件建立一个新的文件
a+”(读写)打开一个文件,在文件尾进行读写建立一个新的文件
rb+”(读写)为了读和写打开一个二进制文件出错
wb+”(读写)为了读和写,新建一个新的二进制文件建立一个新的文件
ab+”(读写)打开一个二进制文件,在文件尾进行读和写建立一个新的文件

ps:
除了有关追加的,其余的像w和r的,在使用存入的时候会清空里面的数据,而不会保留,想要保留,要使用追加

/* fopen fclose example */
#include <stdio.h>
int main ()
{
	FILE * pFile;
	//打开文件
	pFile = fopen ("myfile.txt","w");
	//文件操作
	if (pFile!=NULL)
	{
		fputs ("fopen example",pFile);
		//关闭文件
		fclose (pFile);
	}
	return 0;
}

在这里插入图片描述

4.4 文件的路径

C语言文件的路径指向文件在计算机中的位置。路径可以是绝对路径,也可以是相对路径。

绝对路径是从计算机文件系统的根目录开始的完整路径。例如,Windows系统中的绝对路径可能是"C:\Users\Administrator\Desktop\example.c",而Unix/Linux系统中的绝对路径可能是"/home/user/example.c"

相对路径是相对于当前工作目录的路径。当前工作目录是执行程序或脚本的位置。例如,当前工作目录是"/home/user",文件位于当前工作目录下的子目录"code"中,则相对路径可能是"code/example.c"

在C语言中,使用文件操作函数打开、读取和写入文件时,需要提供文件的路径作为参数。使用绝对路径可以确保准确找到文件,而使用相对路径可以简化文件路径的书写。

在VS中,路径需要双斜杠// .表示当前路径 ..表示上一级路径

绝对路径
在这里插入图片描述
相对路径

当前路径的上一级路径的上一级路径
在这里插入图片描述

五、 文件的顺序读写

5.1 顺序读写函数介绍

函数名功能适用于
fgetc字符输入函数所有输入流
fputc字符输出函数所有输出流
fgets文本行输入函数所有输入流
fputs文本行输出函数所有输出流
fscanf格式化输入函数所有输入流
fprintf格式化输出函数所有输出流
fread二进制输入文件
fwrite二进制输出文件

所有流 分为标准输入输出流和文件输入输出流

上面说的适用于所有输入流一般指适用于标准输入流和其他输入流(如文件输入流);

所有输出流一般指适用于标准输出流和其他输出流(如文件输出流)。

fgetc

见下面

fputc

c语言的fputc函数用于将一个字符写入到文件中。该函数的原型如下:

int fputc(int c, FILE *stream);

其中,c表示要写入的字符,stream表示要写入的文件指针。该函数返回写入的字符,如果出现错误,则返回EOF

下面是一个示例:

#include <stdio.h>

int main() {
    FILE *fp;
    char c = 'A';

    // 打开文件
    fp = fopen("file.txt", "w");

    // 写入字符
    fputc(c, fp);

    // 关闭文件
    fclose(fp);

    return 0;
}

上述示例将字符'A'写入到名为file.txt的文件中。

fgets

见下面

fputs

C语言的fputs函数用于将字符串写入到文件中。该函数的原型如下:

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

其中,str表示要写入的字符串,stream表示要写入的文件指针。该函数返回非负值表示成功,返回EOF表示出现错误。

下面是一个示例:

#include <stdio.h>

int main() {
    FILE *fp;
    char str[] = "Hello, World!";

    // 打开文件
    fp = fopen("file.txt", "w");

    // 写入字符串
    fputs(str, fp);

    // 关闭文件
    fclose(fp);

    return 0;
}

上述示例将字符串"Hello, World!"写入到名为file.txt的文件中。

fscanf

C语言中的 fscanf 函数用于从文件中读取数据。它的格式与 scanf 函数类似,但需要指定要读取的文件。

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

其中,stream 是指向要读取的文件的指针,format 是要读取的数据的格式字符串,... 表示可以接收任意数量和类型的参数,用来接收读取的数据。

下面是一个示例:

#include <stdio.h>

int main() {
    FILE *file;
    int num1, num2;
    
    file = fopen("data.txt", "r"); // 打开文件
    
    if(file == NULL) {
        printf("无法打开文件\n");
        return 1;
    }
    
    fscanf(file, "%d %d", &num1, &num2); // 从文件中读取两个整数
    
    printf("从文件中读取的两个整数分别为:%d 和 %d\n", num1, num2);
    
    fclose(file); // 关闭文件
    
    return 0;
}

上述示例中,我们首先使用 fopen 函数打开名为 "data.txt" 的文件。然后,使用 fscanf 函数从文件中读取两个整数,并将它们存储到变量 num1num2 中。最后,使用 printf 函数将读取的两个整数输出到屏幕上。

需要注意的是,在使用 fscanf 函数读取文件数据之前,我们需要确保文件已经成功打开,并且在使用完毕后需要使用 fclose 函数关闭文件。

fprintf

C语言中的 fprintf 函数用于将指定的数据按照指定的格式写入到文件中。它的格式与 printf 函数类似,但需要指定要写入的文件。

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

其中,stream 是指向要写入的文件的指针,format 是要写入的数据的格式字符串,... 表示可以接收任意数量和类型的参数,用来传递要写入的数据。

下面是一个示例:

#include <stdio.h>

int main() {
    FILE *file;
    int num = 10;
    
    file = fopen("data.txt", "w"); // 打开文件
    
    if(file == NULL) {
        printf("无法打开文件\n");
        return 1;
    }
    
    fprintf(file, "The number is %d\n", num); // 将整数写入文件
    
    fclose(file); // 关闭文件
    
    return 0;
}

上述示例中,我们首先使用 fopen 函数打开名为 "data.txt" 的文件,并指定以写入方式打开文件。然后,使用 fprintf 函数将整数 num 写入文件,同时按照指定的格式进行格式化输出。最后,使用 fclose 函数关闭文件。

需要注意的是,在使用 fprintf 函数写入文件数据之前,我们需要确保文件已经成功打开,并且在使用完毕后需要使用 fclose 函数关闭文件。

fread

在 C 语言中,fread 函数用于从文件中读取指定数量的数据,并将其存储到缓冲区中。它的函数原型如下:

size_t fread(void *ptr, size_t size, size_t count, FILE *stream);

其中,ptr 是一个指向要读取数据的缓冲区的指针,size 是每个数据项的大小(以字节为单位),count 是要读取的数据项的数量, stream 是一个指向要读取的文件的指针。

fread 函数会返回实际读取的数据项数量,若返回值小于 count,可能是因为已经到达了文件结尾或发生了读取错误。

下面是一个示例,演示如何使用 fread 从文件中读取数据:

#include <stdio.h>

int main() {
    FILE *file;
    int numbers[5];
    
    file = fopen("data.txt", "r"); // 打开文件
    
    if (file == NULL) {
        printf("无法打开文件\n");
        return 1;
    }
    
    fread(numbers, sizeof(int), 5, file); // 从文件中读取5个整数
    
    for (int i = 0; i < 5; i++) {
        printf("%d ", numbers[i]);
    }
    
    fclose(file); // 关闭文件
    
    return 0;
}

在上述示例中,我们首先使用 fopen 函数打开名为 "data.txt" 的文件,并指定以只读方式打开文件。然后,使用 fread 函数从文件中读取 5 个整数,将其存储在 numbers 数组中。最后,使用循环输出读取到的整数。

需要注意的是,在使用 fread 函数读取文件数据之前,我们需要确保文件已经成功打开,并且在使用完毕后需要使用 fclose 函数关闭文件。

fwrite

在 C 语言中,fwrite 函数用于将数据从内存写入到文件中。它的函数原型如下:

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

其中,ptr 是指向要写入的数据的指针,size 是每个数据项的大小(以字节为单位),count 是要写入的数据项的数量,stream 是一个指向要写入的文件的指针。

fwrite 函数会返回实际写入的数据项数量,若返回值小于 count,可能是因为写入错误或者磁盘已满。

下面是一个示例,演示如何使用 fwrite 将数据写入文件:

#include <stdio.h>

int main() {
    FILE *file;
    int numbers[] = {1, 2, 3, 4, 5};
    
    file = fopen("data.txt", "w"); // 打开文件
    
    if (file == NULL) {
        printf("无法打开文件\n");
        return 1;
    }
    
    fwrite(numbers, sizeof(int), 5, file); // 将5个整数写入文件
    
    fclose(file); // 关闭文件
    
    return 0;
}

在上述示例中,我们首先使用 fopen 函数以写入方式打开名为 “data.txt” 的文件。然后,使用 fwrite 函数将 numbers 数组中的 5 个整数写入文件。最后,使用 fclose 函数关闭文件。

需要注意的是,在使用 fwrite 函数写入文件数据之前,我们需要确保文件已经成功打开,并在使用完毕后使用 fclose 函数关闭文件。

5.2 对比一组函数

scanf/fscanf/sscanf
printf/fprintf/sprintf

fscanffprintf ,跟printfscanf 相比 只是前面多了一个文件指针

sscanf

sscanf函数是C语言中的一个输入函数,用于从字符串中按照指定的格式解析数据。它的函数原型为:

int sscanf(const char* str, const char* format, ...);

其中,str是要解析的字符串,format是解析的格式字符串,…表示可变参数列表,表示要解析的数据的地址。

sscanf函数根据format中的格式指定符,从str中读取数据,并将解析出的数据存放在可变参数列表中的相应位置。它可以解析各种类型的数据,比如整数、浮点数、字符等。

下面是一个使用sscanf函数的例子:

#include <stdio.h>

int main() {
    char str[] = "10 3.14 Hello";
    int a;
    float b;
    char c[10];
    sscanf(str, "%d %f %s", &a, &b, c);
    printf("a = %d, b = %f, c = %s\n", a, b, c);
    return 0;
}

输出结果为:

a = 10, b = 3.140000, c = Hello

可以看到,sscanf函数按照指定的格式从字符串中解析出了整数、浮点数和字符串,并赋值给相应的变量。

sprintf

sprintf函数是C语言中的一个输出函数,用于将格式化的数据写入字符串中。它的函数原型为:

int sprintf(char* str, const char* format, ...);

其中,str是要写入的字符串,format是格式化字符串,...表示可变参数列表,表示要写入的数据。

sprintf函数根据format中的格式指定符,将可变参数列表中的数据按照指定格式写入到str中。它可以写入各种类型的数据,比如整数、浮点数、字符串等。

下面是一个使用sprintf函数的例子:

#include <stdio.h>

int main() {
    char str[50];
    int a = 10;
    float b = 3.14;
    char c[] = "Hello";
    
    sprintf(str, "a = %d, b = %f, c = %s", a, b, c);
    
    printf("str = %s\n", str);
    
    return 0;
}

输出结果为:

str = a = 10, b = 3.140000, c = Hello

可以看到,sprintf函数根据指定的格式将整数、浮点数和字符串转换为字符串,并写入到str中。最终str中包含了格式化后的数据。

在这里插入图片描述
fscanf 必须和 fprintf 的格式相同,不然会出现读入错误的问题
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

5.3标准的数据拷贝

在这里插入图片描述

六、 文件的随机读写

在文件中,每读取一个字符,文件中的光标都会向后移动一位

在这里插入图片描述

6.1 fseek

根据文件指针的位置和偏移量来定位文件指针。

int fseek ( FILE * stream, long int offset, int origin ); 

设置的指针的位置是 起始位置 + 偏移量 ;

其中的 int origin参数就是 起始位置 , 有以下三种选择 :
文件头 SEEK_SET 0
当前位置 SEEK_CUR 1
文件尾 SEEK_END 2
long offset 偏移量参数 , 可以为正数 , 也可以为负数 ;

如果执行成功 , 则返回 0 , 失败返回非 0 , 并设置 error 错误代码 ;
例子:

/* fseek example */
#include <stdio.h>
int main ()
{
	FILE * pFile;
	pFile = fopen ( "example.txt" , "wb" );
	fputs ( "This is an apple." , pFile );
	fseek ( pFile , 9 , SEEK_SET );
	fputs ( " sam" , pFile );
	fclose ( pFile );
	return 0;
}

6.2 ftell

返回文件指针相对于起始位置的偏移量

long int ftell ( FILE * stream );

例子:

/* ftell example : getting size of a file */
#include <stdio.h>
int main ()
{
	FILE * pFile;
	long size;
	pFile = fopen ("myfile.txt","rb");
	if (pFile==NULL)
		perror ("Error opening file");
	else
	{
		fseek (pFile, 0, SEEK_END); // non-portable
		size=ftell (pFile);
		fclose (pFile);
		printf ("Size of myfile.txt: %ld bytes.\n",size);
	}
	return 0;
}

6.3 rewind

让文件指针的位置回到文件的起始位置

void rewind ( FILE * stream );

例子:

/* rewind example */
#include <stdio.h>
int main ()
{
	int n;
	FILE * pFile;
	char buffer [27];
	pFile = fopen ("myfile.txt","w+");
	for ( n='A' ; n<='Z' ; n++)
		fputc ( n, pFile);
	rewind (pFile);
	fread (buffer,1,26,pFile);
	fclose (pFile);
	buffer[26]='\0';
	printf(buffer);
	return 0;
}

七、 文件读取结束的判定

在这里插入图片描述

fgetc

在C语言中,fgetc函数用于从文件中读取一个字符。它接受一个文件指针作为参数,并返回文件中的下一个字符(以整数形式)。如果到达文件末尾或发生错误,它返回特殊值EOF(-1)。以下是一个使用示例:

#include <stdio.h>

int main() {
    FILE *file = fopen("example.txt", "r"); // 以只读方式打开文件
    int c;

    if (file == NULL) {
        printf("无法打开文件。");
        return 1;
    }

    while ((c = fgetc(file)) != EOF) {
        printf("%c", c);
    }

    fclose(file); // 关闭文件

    return 0;
}

在这个示例中,程序打开了一个名为"example.txt"的文件,并逐个字符读取其内容,直到达到文件末尾。然后,将每个字符打印到控制台上。最后,关闭文件以释放系统资源。

fgets

在C语言中,fgets函数用于从文件中读取一行文本。它接受三个参数:一个字符数组指针,用于存储读取的字符串;一个整数值,表示要读取的最大字符数(包括空字符);一个文件指针,指定要从中读取的文件。

fgets函数会一直读取字符,直到遇到换行符(包括换行符在内)或达到指定的最大字符数。读取的字符串将存储在指定的字符数组中,并在结束时自动添加一个空字符。

以下是一个使用示例:

#include <stdio.h>

int main() {
    FILE *file = fopen("example.txt", "r"); // 以只读方式打开文件
    char buffer[100];

    if (file == NULL) {
        printf("无法打开文件。");
        return 1;
    }

    while (fgets(buffer, sizeof(buffer), file) != NULL) {
        printf("%s", buffer);
    }

    fclose(file); // 关闭文件

    return 0;
}

在这个示例中,程序打开了一个名为"example.txt"的文件,并逐行读取其内容。读取的每一行被存储在名为buffer的字符数组中,并随后被打印到控制台上。最后,关闭文件以释放系统资源。

7.1 被错误使用的 feof

牢记:在文件读取过程中,不能用feof函数的返回值直接来判断文件的是否结束。

feof 的作用是:当文件读取结束的时候,判断是读取结束的原因是否是:遇到文件尾结束。

  1. 文本文件读取是否结束,判断返回值是否为 EOF ( fgetc ),或者 NULL ( fgets )
    例如:
  • fgetc 判断是否为 EOF .
  • fgets 判断返回值是否为 NULL .
  1. 二进制文件的读取结束判断,判断返回值是否小于实际要读的个数。

例如:

  • fread判断返回值是否小于实际要读的个数。

文本文件的例子:

#include <stdio.h>
#include <stdlib.h>
int main(void)
{
	int c; // 注意:int,非char,要求处理EOF
	FILE* fp = fopen("test.txt", "r");
	if(!fp) {
		perror("File opening failed");
	return EXIT_FAILURE;
	}
	//fgetc 当读取失败的时候或者遇到文件结束的时候,都会返回EOF
	while ((c = fgetc(fp)) != EOF) // 标准C I/O读取文件循环
	{
		putchar(c);
	}
	//判断是什么原因结束的
	if (ferror(fp))
		puts("I/O error when reading");
	else if (feof(fp))
		puts("End of file reached successfully");
	fclose(fp);
}

二进制文件的例子:

#include <stdio.h>
enum { SIZE = 5 };
int main(void)
{
	double a[SIZE] = {1.,2.,3.,4.,5.};
	FILE *fp = fopen("test.bin", "wb"); // 必须用二进制模式
	fwrite(a, sizeof *a, SIZE, fp); // 写 double 的数组
	fclose(fp);
	double b[SIZE];
	fp = fopen("test.bin","rb");
	size_t ret_code = fread(b, sizeof *b, SIZE, fp); // 读 double 的数组
	if(ret_code == SIZE) {
	puts("Array read successfully, contents: ");
	for(int n = 0; n < SIZE; ++n) printf("%f ", b[n]);
		putchar('\n');
	} else { // error handling
	if (feof(fp))
		printf("Error reading test.bin: unexpected end of file\n");
	else if (ferror(fp)) {
	perror("Error reading test.bin");
		}
	}
	fclose(fp);
}

八、 文件缓冲区

ANSIC 标准采用“缓冲文件系统”处理的数据文件的,所谓缓冲文件系统是指系统自动地在内存中为程序中每一个正在使用的文件开辟一块“文件缓冲区”。从内存向磁盘输出数据会先送到内存中的缓冲区,装满缓冲区后才一起送到磁盘上。如果从磁盘向计算机读入数据,则从磁盘文件中读取数据输入到内存缓冲区(充满缓冲区),然后再从缓冲区逐个地将数据送到程序数据区(程序变量等)。缓冲区的大小根据C编译系统决定的。
在这里插入图片描述fflush 刷新缓存区 写入的数据放入缓冲区,放满了才能写,或者刷新缓冲区也能写

#include <stdio.h>
#include <windows.h>
//VS2019 WIN11环境测试
int main()
{
	FILE*pf = fopen("test.txt", "w");
	fputs("abcdef", pf); //先将代码放在输出缓冲区
	printf("睡眠10秒-已经写数据了,打开test.txt文件,发现文件没有内容\n");
	Sleep(10000);
	printf("刷新缓冲区\n");
	fflush(pf); //刷新缓冲区时,才将输出缓冲区的数据写到文件(磁盘)
	//注:fflush 在高版本的VS上不能使用了
	printf("再睡眠10秒-此时,再次打开test.txt文件,文件有内容了\n");
	Sleep(10000);
	fclose(pf);
	//注:fclose在关闭文件的时候,也会刷新缓冲区
	pf = NULL;
	return 0;
}

这里可以得出一个结论:

因为有缓冲区的存在,C语言在操作文件的时候,需要做刷新缓冲区或者在文件操作结束的时候关闭文件。

如果不做,可能导致读写文件的问题。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1398558.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

pearcmd文件包含漏洞

1.什么是pearcmd.php pecl是PHP中用于管理扩展而使用的命令行工具&#xff0c;而pear是pecl依赖的类库。在7.3及以前&#xff0c;pecl/pear是默认安装的&#xff1b;在7.4及以后&#xff0c;需要我们在编译PHP的时候指定--with-pear才会安装 不过&#xff0c;在Docker任意版本…

python 自动化模块 - pyautogui初探

python 自动化模块 - pyautogui 引言一、安装测试二、简单使用三、常用函数总结 引言 在画图软件中使用pyautogui拖动鼠标&#xff0c;画一个螺旋式的正方形 - (源码在下面) PyAutoGUI允许Python脚本控制鼠标和键盘&#xff0c;以自动化与其他应用程序的交互。API的设计非常简…

卡萨帝洗衣机:被模仿也是竞争力

如何用一句话形容某家企业的竞争力和领导地位&#xff1f;“某某一出手&#xff0c;就知有没有。”这句话相当匹配。如果再加一条&#xff0c;“被模仿”也恰到好处。 从顶流公司OpenAI&#xff0c;苹果Apple Vision Pro&#xff0c;再到卡萨帝洗衣机&#xff0c;被跟随、模仿…

thinkadmin表单上传单图,多图,单文件,多文件

{extend name="../../admin/view/main"}{block name=content} <form action="{:sysuri()}" class="layui-card layui-form" data-auto="tr

iPerf3 使用指南

文章目录 iPerf3 使用指南1 iPerf3 简介2 安装指令2.1 Windows2.2 Linux 3 入门用法4 进阶用法4.1 启动服务端4.2 TCP 带宽测试4.3 UDP 带宽测试 5 iPerf3 命令说明 iPerf3 使用指南 1 iPerf3 简介 iPerf3 是用于主动测试 IP 网络上最大可用带宽的工具。它支持时序、缓冲区、…

Linux编写简易shell

思路&#xff1a;​ ​ ​ 所以要写一个shell&#xff0c;需要循环以下过程:​ 获取命令行解析命令行建立一个子进程&#xff08;fork&#xff09;替换子进程&#xff08;execvp&#xff09;父进程等待子进程退出&#xff08;wait&#xff09; 实现代码&#xff1a;​ #inc…

AI量化交易案例

量化交易 案例介绍 1.1 案例说明 机器学习与人工智能在金融领域已有成熟的应用。用统计模型来预测股票等金融产品的价格并自动交易&#xff0c;这是其中的经典问题。价格预测的模型是这个应用场景中的核心问题&#xff0c;在预测价格变化的基础上&#xff0c;通过一定的交易规则…

给视频添加srt字幕,为你的创作加上心声

无论你是分享生活点滴、教学知识&#xff0c;还是传递某种情感&#xff0c;总会有那么一刹那&#xff0c;言语显得如此苍白无力。而srt字幕就像是一位翻译官&#xff0c;用最恰当、最直接的文字&#xff0c;把你所要表达的意思准确的传递给观众。 所需工具&#xff1a; 一个【…

[C#]winform部署openvino调用padleocr模型

【官方框架地址】 https://github.com/PaddlePaddle/PaddleOCR 【算法介绍】 OpenVINO和PaddleOCR都是用于计算机视觉应用的工具&#xff0c;但它们有不同的特点和用途。OpenVINO是一个由Intel开发的开源工具套件&#xff0c;主要用于加速深度学习推理&#xff0c;而PaddleOC…

MySQL---视图索引

表定义&#xff1a; 学生表&#xff1a;Student (Sno, Sname, Ssex , Sage, Sdept) 学号&#xff0c;姓名&#xff0c;性别&#xff0c;年龄&#xff0c;所在系 Sno为主键 课程表&#xff1a;Course (Cno, Cname,) 课程号&#xff0c;课程名 Cno为主键 学生选课表&#xff1a;S…

DolphinDB学习(0):DolphinDB基本概述

DolphinDB的学习难度不小&#xff0c;主要是写法比较多&#xff0c;官方示例是一次性给一大堆代码&#xff0c;在没有成体系的学习基础的前提下&#xff0c;总有种力不从心的感觉&#xff0c;所以博主汇总这一个系列的文章&#xff0c;尝试从最简单的基础常规操作开始&#xff…

css绘制下拉框头部三角(分实心/空心)

1:需求图: 手绘下拉框 带三角 2:网上查了一些例子,但都是实心的, 可参考,如图: (原链接: https://blog.csdn.net/qq_33463449/article/details/113375804) 3:简洁版的: a: 实心: <view class"angle"/>.angle{width:0;height:0;border-left: 10px solid t…

安全基础~攻防特性3

文章目录 SSTI(模板注入)1. 简介2. 成因3. 常见框架存在注入4. 判断存在SSTI SSTI(模板注入) 1. 简介 (Server-Side Template Injection) 服务端模板注入 1、使用框架&#xff08;MVC的模式&#xff09;&#xff0c;如python的flask&#xff0c;php的tp&#xff0c;java的sp…

Flask 3.x log全域配置(包含pytest)

最近使用到flask3.x&#xff0c;配置了全域的log&#xff0c;这边记录下 首先需要创建logging的配置文件&#xff0c;我是放在项目根目录的&#xff0c; Logging 配置 logging.json {"version": 1, # 配置文件版本号"formatters": {"default&qu…

目标检测难题 | 小目标检测策略汇总

大家好&#xff0c;在计算机视觉中&#xff0c;检测小目标是最有挑战的问题之一&#xff0c;本文给出了一些有效的策略。 从无人机上看到的小目标 为了提高模型在小目标上的性能&#xff0c;本文推荐以下技术&#xff1a; 提高图像采集的分辨率 增加模型的输入分辨率 tile你…

C++PythonC# 三语言OpenCV从零开发(3):图像读取和显示

文章目录 相关链接前言Mat是什么读取图片CC#Python 灰度处理CCSharpPython 打印图像信息CCsharpPython 总结 相关链接 C&Python&Csharp in OpenCV 专栏 【2022B站最好的OpenCV课程推荐】OpenCV从入门到实战 全套课程&#xff08;附带课程课件资料课件笔记&#xff09; …

项目上线存在的缓存问题以及存在的debugger和console.log等问题

下载uglifyjs-webpack-plugin插件 在vue.config文件中进行配置 publicPath: process.env.NODE_ENV production ? ./ : /,outputDir: n-sim-ipc-manage-build,productionSourceMap: false,configureWebpack: config > {//打包文件增加hashconfig.output.filename js/[nam…

微电网优化MATLAB:基于麻雀搜索算法SSA的微电网优化调度(提供MATLAB代码)

一、微网系统运行优化模型 参考文献&#xff1a; [1]李兴莘,张靖,何宇,等.基于改进粒子群算法的微电网多目标优化调度[J].电力科学与工程, 2021, 37(3):7 二、麻雀搜索算法简介 麻雀搜索算法 (Sparrow Search Algorithm, SSA) 是一种新型的群智能优化算法&#xff0c;于2020…

博达V900远程透传模块与台达PLC远程上下载程序,远程在线调试程序

准备工作 一台可联网操作的电脑一台单网口的远程透传网关及博达远程透传配置工具网线一条&#xff0c;用于实现网络连接和连接PLC一台台达PLC及其编程软件WPLSoft一张4G卡或WIFI天线实现通讯(使用4G联网则插入4G SIM卡&#xff0c;WIFI联网则将WIFI天线插入USB口&#xff09; …

利用Pytest插件pytest-asyncio实现异步代码测试

在现代异步编程的时代,Python中的 pytest-asyncio 插件为我们提供了在异步代码中进行测试的强大工具。本文将深入介绍 `pytest-asyncio` 插件的基本用法和实际案例,助你更好地理解和运用异步测试。 什么是pytest-asyncio? pytest-asyncio 是Pytest的一个插件,它为异步代码…