C语言文件操作

C语言与文件操作 计算机中能在内存中存储数据,但是内存的大小为8~16G,这个大小如果被用完将会溢出数据,那么我们要怎么储存更大的数据呢?这就要将数据存储到硬盘中。如果要将数据存储到硬盘中,C语言提供了文件操作函数,可以把数据储存到文件中。这样就解决了内存不够大的问题。 阅读详情

一、文件基础知识

1. 什么是文件

在日常生活中我们所说的文件就是电脑磁盘上的文件,但是在程序设计中,我们一般谈的文件有两种:程序文件和数据文件(从文件功能的角度来分类的)

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

后缀为.exe)

数据文件:文件的内容不一定是程序,也可能是程序运行时读写的数据,比如程序运行需要从中读取数据的文件,或者输出内容的文件,以下讨论的都是数据文件。

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

文件名包含3部分:文件路径+文件名主干+文件后缀,例如: c:\code\test.txt

2. 为什么使用文件

假设你学习了结构体和动态内存管理的相关知识,现在要利用这些知识要写一个通讯录的小程序,当通讯录运行起来后,可以给通讯录中增加、删除联系人数据,此时数据是存放在内存中的,当程序退出的时候,通讯录中的数据自然就不存在了,等下次再次运行通讯录程序的时候,数据又得重新录入,这样的通讯录完全没有实用价值。

我们在想既然是通讯录就应该把信息记录下来,只有我们自己选择删除数据的时候,数据才不复存在。 这就涉及到了数据持久化的问题,我们一般数据持久化的方法有两种:把数据存放在磁盘文件和存放到数据库的方式。

使用文件我们可以将数据存放到电脑的硬盘上,做到数据的持久化


3. 文件的打开和关闭

  • 文件信息区和文件指针

在计算机系统中,文件信息区和文件指针是用于管理和操作文件的关键元素

  1. 文件信息区:当一个文件被打开时,操作系统会创建一个文件信息区,也被称为文件控制块。这个区域包含了关于文件的各种信息,比如文件名、文件大小、文件创建和修改的日期和时间、文件的物理位置等。这些信息是保存在一个结构体变量中的,该结构体类型是由系统声明的,取名为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结构的变量,这样使用起来更加方便。

  1. 文件指针:文件指针是一个指向文件中特定位置的指针,通常用于读取或写入文件。当你打开一个文件时,文件指针通常会被初始化为指向文件的开头。然后,随着你读取或写入文件,文件指针会向前移动,始终指向下一个将要被读取或写入的位置,你也可以通过特定的操作来移动文件指针,例如跳转到文件的某个特定位置。

这两个概念在文件系统操作中是非常重要的,了解它们可以帮助你更好地理解如何在程序中处理文件。

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

FILE* pf//文件指针变量

定义pf是一个指向FILE类型数据的指针变量,可以使pf指向某个文件的文件信息区(是一个结构体变

量),通过该文件信息区中的信息就能够访问该文件,也就是说,通过文件指针变量能够找到与它关联

的文件。

在这里插入图片描述

  • 文件的打开和关闭

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

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

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

//打开文件
FILE* fopen ( const char * filename, const char * mode );
// filename:文件名(可以是绝对路径或相对路径)
// mode:文件打开方式("r"/"w"/"a"/"rb"/"wb".....)
// 打开成功返回文件指针,否则返回NULL

//关闭文件
int fclose ( FILE * stream );
// stream:指向文件结构的指针

文件打开方式如下:

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

具体实例如下:

/* fopen fclose example */
#include <stdio.h>
int main ()
{
    FILE* pFile = fopen ("myfile.txt","w"); //只写方式打开文件并接收文件指针
    if (pFile != NULL)//打开成功
    {
        //文件操作
        fputs ("fopen example",pFile);
        //关闭文件
        fclose (pFile);
        pFile = NULL;
    }
    return 0;
}

以只读的形式打开,如果你的代码路径下没有 test.txt 这个文件,它会先创建一个 test.txt 文件,然后再把fopen example 这句话写入到 test.txt 中。


二、文件的顺序读写

1、顺序读写相关函数

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

2、文件读写以及流的概念

文件读写

我们知道,在程序中产生的数据都是存储在内存中的,因为数据需要占用空间,而程序设计中的空间全部由内存分配;而文件是存在于硬盘中的;对于我们程序员来说,我们是编写代码的人,所以我们是以内存的视角来看待文件中的数据的,对我们来说:文件的写代表着把程序中产生的数据写入到硬盘的文件中去,进行的是输出操作;文件的读代表着把硬盘中文件的数据读入到内存中来,进行的是输入操作

在这里插入图片描述

流的概念

在计算机科学中,“流”(stream)是一个抽象的概念,用于处理输入/输出 (I/O) 操作,尤其是读写数据。这个概念来源于流水线(pipeline)的理念,数据可以被视为从源点"流"到目标点

流可以分为输入流和输出流:

  • 输入流:输入流从数据源(例如,文件、键盘输入、网络连接等)读取数据。你可以想象数据是从数据源"流入"你的程序。
  • 输出流:输出流将数据写入目标(例如,文件、控制台、网络连接等)。你可以想象数据是从你的程序"流出"到目标。
  • 流的优点

使用流的主要优点之一是它们提供了一种抽象的方法来处理输入/输出,这使得你的程序可以不必关心数据来自哪里,或者将要去哪里。我们程序员只需要关注如何与流进行数据交互就行了,从流到外部设备这一过程C语言底层会自动帮我们实现。例如,你可以使用相同的代码来从文件读取数据,然后再将数据写入网络连接。这种统一性使得编程更加方便,并提高了代码的可重用性。

3、fgetc 与 fputc

  • 函数功能

fgetc:从文件中读取一个字符到内存中;fputc:从内存中输出一个字符到文件中。

  • 函数原型
int fgetc( FILE* stream );
// stream 对应文件指针
// int 函数返回值,读取成功时返回对应字符ASCII值,读取失败或者遇见文件末尾时返回EOF

int fputc( int c, FILE* stream );
// c 要输出的字符
// stream 对应文件指针
// int 函数返回值,返回输出的字符
  • 函数使用
int main()
{
	//打开文件
	FILE* pf = fopen("test.txt", "w");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//向文件中写入字符
	fputc('a', pf);
	fputc('b', pf);

	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}
int main()
{
	//打开文件
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//从文件中读取字符
	printf("%c\n", fgetc(pf));
	printf("%c\n", fgetc(pf));

	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}

4、fgets 与 fputs

  • 函数功能

fgets:从文件中读取一行字符到内存中;fputs:从内存中输出一行字符到文件中。

  • 函数原型
char *fgets( char* string, int n, FILE* stream );
// string 数据的存储位置 
// n: 要读取的最大字符数
// stream 对应文件指针
// char* 函数返回值,读取成功返回字符串首地址,失败或者遇到文件末尾返回NULL

int fputs( const char *string, FILE* stream );
// string 要输出的字符串的首地址
// stream 对应文件指针
// int 函数返回值,输出成功,返回一个非负值,否则返回EOF
  • 函数使用
int main()
{
	//打开文件
	FILE* pf = fopen("test.txt", "w");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//向文件中写入一行字符
	fputs("abcdef", pf);
	fputs("12345", pf);

	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}
int main()
{
	//打开文件
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//向内存中存入一行字符
	char buf[20] = { 0 };
	fgets(buf, 20, pf);
	printf("%s", buf);
	fgets(buf, 20, pf);
	printf("%s", buf);

	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}

在这里插入图片描述

  • 注意事项
  1. 文件的读和写不能同时进行;
  2. 对于同一个文件,当我们以写的形式打开时,操作系统首先会将该文件中原有的数据全部清除,然后再执行后续操作;
  3. 对于 fgets 函数来说,实际从文件中读取的字符的个数会比指定的字符个数少一个,因为最后一个字符会被用于字符串的结束标志’\0’;

5、fscanf 与 fprintf

  • 函数功能

fscanf:从文件中读取格式化的数据到内存中;fprintf:把内存中的数据格式化地写入到文件中;

  • 函数原型
int fscanf( FILE *stream, const char *format [, argument ]... );
// stream 对应文件指针
// format 格式控制字符串,和scanf一样
// argumeng 可选参数
// int 函数返回值,读取成功时,函数返回成功填充的参数列表的项数,读取失败或者遇到文件末尾返回EOF

int fprintf( FILE *stream, const char *format [, argument ]... );
// stream 对应文件指针
// format 格式控制字符串,和printf一样
// int 函数返回值,输出成功时,返回输出的字符总数,失败时返回一个负数
  • 函数使用

fscanf 和 fprintf 的使用与 scanf 以及 printf 函数的使用基本相同,只是第一个参数多了一个文件指针而已。

struct Stu
{
	char name[20];
	int age;
	char sex[10];
};

int main()
{
	struct Stu stu = { "zhangsan", 20, "nan" };
	//打开文件
	FILE* pf = fopen("test.txt", "w");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//向文件中格式化写入数据
	fprintf(pf, "%s %d %s", stu.name, stu.age, stu.sex);

	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}
struct Stu
{
	char name[20];
	int age;
	char sex[10];
};

int main()
{
	struct Stu stu = { 0 };
	//打开文件
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//从文件中格式化读取数据存到stu变量
	fscanf(pf, "%s %d %s", stu.name, &(stu.age), stu.sex);
	printf("%s %d %s\n", stu.name, stu.age, stu.sex);

	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}

6、fwrite 与 fread

  • 函数功能

fwrite:以二进制的形式向文件中写入数据;fread:以二进制的形式从文件中读取数据;

  • 函数原型
size_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream );
// ptr    数据的起始地址
// size   每个元素的大小
// count  元素的个数
// stream 对应文件指针
// size_t 函数返回值,返回成功写入的元素个数

size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );
// 参数与 fwrite 相同
// size_t 函数返回值,返回成功读取的元素总数
  • 函数使用
struct Stu
{
	char name[20];
	int age;
	char sex[10];
};

int main()
{
	struct Stu stu = { "zhangsan", 20, "nan" };
	//打开文件
	FILE* pf = fopen("test.txt", "w");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//以二进制的形式向文件中写入数据
	fwrite(&stu, sizeof(struct Stu), 1, pf);

	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}
struct Stu
{
	char name[20];
	int age;
	char sex[10];
};

int main()
{
	struct Stu stu = { 0 };
	//打开文件
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//以二进制的形式从文件中读取数据
	fread(&stu, sizeof(struct Stu), 1, pf);
    //打印数据
	printf("%s %d %s\n", stu.name, stu.age, stu.sex);

	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}

7、拓展:sscanf 与 sprintf

  • 函数功能

sscanf:从字符串中读取格式化的数据;sprintf:将一组格式化的数据转换为字符串;

  • 函数原型
int sscanf( const char *buffer, const char *format [, argument ] ... );
// buffer   字符串的首地址
// format   格式控制字符串
// argumeng 可选参数
// int      函数返回值,成功时,函数返回成功填充的参数列表的项数,失败返回EOF

int sprintf( char *buffer, const char *format [, argument] ... );
// 参数与 sscanf 函数相同
// int 函数返回值,成功时,返回转换的字符总数,失败则返回一个负数
  • 函数使用
struct Stu
{
	char name[20];
	int age;
	char sex[10];
};

int main()
{
	struct Stu stu = { "zhangsan", 20, "nan" };
	char str[50];  //定义一个字符数组,用来存储从结构体中读取的数据
	//将一组格式化的数据转换为字符串
	sprintf(str, "%s %d %s", stu.name, stu.age, stu.sex);
	printf("%s\n", str);
	//将一个字符串中的数据格式化
	struct Stu stu1 = { 0 };
	sscanf(str, "%s %d %s", stu1.name, &(stu1.age), stu1.sex);
	printf("%s %d %s\n", stu1.name, stu1.age, stu1.sex);
	return 0;
}

  • 注意事项
  • scanf :从标准输入流读取格式化的数据
    printf:向标准输出流写格式化的数据
  • fscanf:适用于所有输入流的格式化输入函数
    fprintf:适用于所有输出流的格式化输出函数
  • sscanf:从字符串中读取格式化的数据
    sprintf:将格式化的数据,转换成字符串

三、文件的随机读写

1、fseek

  • 函数功能

给定文件指针起始位置和偏移量来将文件指针移动到指定位置

  • 函数原型
int fseek( FILE *stream, long offset, int origin );
# stream 对应文件指针
# offset 相对于 origin 参数的偏移量
# origin 偏移量的参考位置
# int 函数返回值,设置成功返回0,否则返回非0
origin变量取值参考位置
SEEK_SET文件的起始位置
SEEK_CUR文件指针的当前位置
SEEK_END文件的末尾
  • 函数使用
int main()
{
	FILE* pf = fopen("test.txt", "w");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}

    fputs ( "This is an apple." , pFile );
    fseek ( pFile , 9 , SEEK_SET );
    fputs ( " sam" , pFile );
    
	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}
int main()
{
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}

	char arr[20] = { 0 };
	fgets(arr, 20, pf);
	printf("%s\n", arr);

	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}

在这里插入图片描述

2、ftell

  • 函数功能

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

  • 函数原型
long int ftell ( FILE * stream );
# stream 对应函数指针
# long int 函数返回值,正常时返回函数指针相对于起始位置的偏移量,出错时返回-1L
  • 函数使用

应用:求文件大小

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

在这里插入图片描述

在这里插入图片描述

3、rewind

  • 函数功能

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

  • 函数原型
void rewind ( FILE * stream );
  • 函数使用
int main()
{
	int n;
	
	char buffer[27];
	//以读写的方式打开文件
	FILE* pFile = fopen("test.txt", "w+");
	//将字符 'A' - 'Z' 写入到文件中
	for (n = 'A'; n <= 'Z'; n++)
		fputc(n, pFile);
	//使文件指针回到文件起始位置
	rewind(pFile);
	//读数据
	fread(buffer, 1, 26, pFile);
	buffer[26] = '\0';
	puts(buffer);
	//关闭文件
	fclose(pFile);
	pFile = NULL;
	return 0;
}

四、文件进阶知识

1. 文本文件和二进制文件

字符在文件中一律以ASCII形式存储,数值型数据既可以看作字符用ASCII形式存储,也可以直接转换为二进制形式存储。

例如有整数10000存储在内存,如果把它看作字符以ASCII码的形式输出到磁盘,则磁盘中占用5个字节(每个字符一个字节),而以二进制形式输出,则在磁盘上只占4个字节。

在这里插入图片描述

根据数据的组织形式,数据文件被称为文本文件或者二进制文件。数据在内存中都是以二进制的形式存储,如果不加转换地输出到磁盘,就是二进制文件。如果要求在外存上以ASCII码的形式存储,则需要在存储前转换。以ASCII字符的形式存储的文件就是文本文件。

2. 文件读取结束的判定

  1. 若要检查文本文件读取是否结束,判断返回值是否为 EOF (fgetc),或者是否为 NULL (fgets);

  2. 若要检查二进制文件的读取是否结束,判断返回值是否小于实际要读的个数;

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


通过以上方法确定了文件读取结束后,就可以用以下函数判断文件读取结束的原因

ferror 和 feof

  • 函数功能

当文件读取结束时,判断读取结束的原因

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

ferror:当文件读取结束的时候,判断读取结束的原因是否是:发生读取错误。

  • 函数原型
int feof( FILE *stream );
# int 函数返回值,如果当前位置是文件末尾,返回非0,否则返回0

int ferror( FILE *stream );
# int 函数返回值,如果当前位置读取发生错误,返回非0,无错误返回0

在文件的使用中,feof 函数的返回值常被错误地认为是用来判断文件是否读取结束的,牢记:在文件读取过程中,不能用 feof 函数的返回值直接来判断文件是否读取结束,而是应当用于在确认文件读取结束后,判断是因为读取失败而结束,还是因为遇到文件尾而结束;

  • feof 的正确使用

文本文件为例子:

int main(void)
{
	int c; //把c定义为int,使其有能力接受EOF(-1)
	FILE* fp = fopen("test.txt", "r");
	if (fp == NULL) 
	{
		perror("File opening failed");
		return EXIT_FAILURE;
	}
	//fgetc 当读取失败的时候或者遇到文件结束的时候,都会返回EOF
	while ((c = fgetc(fp)) != EOF) // 标准C I/O读取文件循环
	{
		putchar(c);
	}
	//循环结束,说明文件读取失败,判断是什么原因结束的
	if (ferror(fp))  //ferror(fp)为真,说明由读取失败引起
		puts("I/O error when reading");
	else if (feof(fp))  //feof(fp)为真,说明由遇到文件尾引起
		puts("End of file reached successfully");
	fclose(fp);
	fp = NULL;
}

二进制文件为例子:

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); // 向文件中以二进制的形式写入一个数组的数据
	fclose(fp);
	fp = NULL;

	double b[SIZE];
	fp = fopen("test.bin", "rb");
	size_t ret_code = fread(b, sizeof *b, SIZE, fp); // 从文件中读取二进制的数据
	if (ret_code == SIZE) //如果fread函数的返回值等于参数SIZE,说明正常读取
    {  
		puts("Array read successfully, contents: ");
		for (int n = 0; n < SIZE; ++n) 
			printf("%f ", b[n]);
		putchar('\n');
	}
	else   //否则,遇到错误或者文件尾
	{
		if (feof(fp))  //表示遇到文件尾
			printf("Error reading test.bin: unexpected end of file\n");
		else if (ferror(fp))  //表示遇到错误
			perror("Error reading test.bin");
	}
	fclose(fp);
	fp = NULL;
}

3. 文件缓冲区

什么是文件缓冲区

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

在这里插入图片描述

文件缓冲区的好处

文件缓冲区(File Buffer)在计算机系统中扮演着非常重要的角色。以下是文件缓冲区存在的主要原因和好处:

  • 提升性能

文件操作通常涉及到硬盘驱动器(或其他存储设备),而这些设备的读写速度远低于内存(RAM)的速度。如果每次读写操作都直接从硬盘中进行,那么性能会受到严重影响。而文件缓冲区位于内存中,读写速度远高于硬盘。

另外磁盘I/O操作是相当耗时的,通过在内存中创建一个缓冲区,我们可以一次性地读取或写入大量数据,而不是一次只处理一个字符或一个字节,这样可以大大减少必须进行的磁盘I/O操作次数,从而大幅提升性能。

  • 数据安全

缓冲区也可以提供一定程度的数据安全。例如,当你正在写入一个文件时,如果突然发生电源断电或系统崩溃,那么直接写入硬盘的数据可能会丢失或者损坏。但是,如果你先写入缓冲区,然后再将缓冲区的数据写入硬盘,那么即使在写入过程中发生问题,你也可以从缓冲区中恢复数据。

  • 数据处理

在某些情况下,你可能需要对数据进行处理(例如,压缩或者加密)然后再写入硬盘。使用缓冲区,你可以先将数据写入缓冲区,然后在缓冲区中进行处理,最后再将处理后的数据写入硬盘。

  • 流式操作

缓冲区也支持流式操作。通过使用缓冲区,你可以从一个输入流读取数据,然后写入到一个输出流,而不需要一次性处理所有的数据,这对于处理大文件或者网络数据流非常有用。

  • 统一接口

缓冲区提供了一种统一的接口来处理文件和内存中的数据,使得编程更加方便。例如,许多编程语言提供了缓冲区相关的类和函数,你可以使用这些功能来进行高效的文件操作。


可以通过运行下面这段代码直观地感受到文件缓冲区的存在:

#include <stdio.h>
#include <windows.h>
//VS2022 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;
}

在这里插入图片描述

注意事项

虽然文件缓冲区拥有许多优势,但也有一些潜在的问题。例如,如果不及时刷新缓冲区(例如,使用fflush函数)或者在文件操作结束的时候关闭文件,那么可能会导致数据在程序崩溃或电源中断等情况下丢失,因此,使用文件缓冲区时需要谨慎处理。

XGBoost算法案例 - 红酒品质分类 数据集共包含 11 个特征,共计 3269 条数据. 我们通过训练模型来预测红酒的品质, 品质共有 6 个各类别,分别使用数字: 0、1、2、3、4、5 来表示。 阅读详情

相关推荐

IATF16949核心职位全解析

TM / Top MgmtMR / QMRProcess OwnerQMQAQCSQECQEPQEPETEMEIEPM / PJMFMEA ModeratorMSA CoordinatorSPC CoordinatorCM / CCB内审员CP / CPK

weixin_49938552的博客 972

C语言文件操作详解

如果你是一个C语言初学者,那么你一定发现,目前我们的C语言程序只会在执行后自动退出,而不会保存数据及运行结果,那么如何才能保存数据呢?为了保存数据,我们可以用到文件操作。

Eliauk_U的博客 2万+

ST-LINK调试STM32H743必看:CubeMX工程中缺失的这行代码导致程序跑飞

本文深入剖析了使用ST-LINK调试STM32H743时,因CubeMX工程中缺失电源电压档位配置代码而导致程序跑飞或出现“Can not access memory”错误的问题。文章解释了H7系列电源与时钟耦合的核心原理,提供了具体的代码修复方案和系统化的调试排查思路,帮助开发者从根本上解决这一常见调试困境。

weixin_29191669的博客 280

C语言常见文件操作函数总结详解

C语言文件操作函数,怕是很多人的痛,因为在各种地方都能用到,说的简单一点在某些课堂作业上,可能会让你去操作一个txt文档的读写,再就是课程设计时候老师要求把数据存放到文本文件中,我曾经见过一个粉丝问我问题,他们的老师要求简直离谱,是必须使用文本文档来存放数据!我直接就????????????,怎么还有这种要求阿?数据库操作也不是不行阿,非得用文本文件,虽说这样比较死板,但也侧面反映出了教学对文件操作的重视,再往深了说,比如你要解析某个文件格式,比如常见的PE文件,关于文件的读写几乎是必不可少的一步,首先得读

KOOKNUT的博客 2317

手把手调试:如何为高通Hypervisor上的GuestOS添加一个自定义的HAB服务通道

本文详细介绍了如何在高通Hypervisor环境下为GuestOS添加自定义HAB服务通道的全过程。从HAB通信框架的核心概念解析到设备树节点的动态注入机制,再到物理通道的内核层实现和用户层测试,提供了完整的开发案例和调试技巧,帮助开发者高效构建定制化通信服务。

weixin_27066963的博客 371

商城系统全链路压测实战指南

全链路压测是模拟真实用户行为和生产环境流量,验证整个系统在高压下的稳定性和性能表现的关键手段。

monk all the way 1228

C语言之文件操作

本文将全面详细的讲述C语言文件操作的基础知识,包括所右顺序读写的函数介绍以及随机读写的函数介绍,字数较多,感谢支持

x_p96484685433的博客 1379

华为AC外置Portal认证方案配置步骤指南

华为AC外置Portal认证方案配置步骤指南

m0_46129105的博客 7665

c语言中的文件操作

引入: 磁盘上的文件都是文件。 对于日常生活中,我们在使用电子设备的时候,用到某个软件或者应用的时候,总是发现他们会在本地占用空间,即文件,是不是打开软件后,先前保留的数据都不见了呢?不是的,这些数据是被存放在文件里面的。 之前我们制作的动态储存版的通讯录(一个小项目,数据只能储存到内存中),程序是不是只要一关闭,保存的数据下次打开就消失了。这是因为没有将其数据保存在文件中,而是内存中,结束程序内存的空间也自然被释放,从而无法保留。 那么如果想要改进这个通讯录自然要加上文件操作的函数让其数据保留

QiHai的博客 6384

Python 陌生代码库阅读之道:从零起步到一周掌控 5 万行老项目的实战策略

文中特别强调"自顶向下+画图+注释"的基础阅读心法,并提供了具体的代码示例和命令行技巧。对于大型项目,建议先建立核心流程的骨架认知,再逐步填充细节,同时注重文档化和测试覆盖率的提升。 掌握这套方法后,开发者可以将陌生代码库的阅读效率提升3倍以上,在一周内建立起对5万行级别项目的整体掌控力。

铭渊老黄 506

嵌入式工程师成长之路(10)——项目举例

送给大学毕业后找不到奋斗方向的你(每周不定时更新)

云轩阁 5万+

C语言文件操作总结

C语言文件操作 一、标准文件的读写 1.文件的打开 fopen() 文件的打开操作表示将给用户指定的文件在内存分配一个FILE结构区,并将该结构的指针返回给用户程序,以后用户程序就可用此FILE指针来实现对指定文件的存取操作了。当使用打开函数时,必须给出文件名、文件操作方式(读、写或读写),如果该文件名不存在,就意味着建立(只对写文件而言,对读文件则出错),并将文件指针指向文件开头。若已有一个同名...

Sock的博客 1086

【重温童年】基于tkinter模块设计的Q宠大乐斗武器升星模拟器:重温经典,畅享休闲时光

与传统的Q宠大乐斗不同,这款模拟器还加入了一个创新的功能——自定义升星概率。玩家可以根据自己的喜好和策略,为不同的武器设置不同的成功率和降级率。比如,你可以将“嗜血”这把武器的升星难度设置得极高,以体现其稀有性和强大威力;也可以将“平底锅”这样的普通武器设置得相对容易升星,让玩家在升级过程中感受到更多的成就感。这种自定义的概率设置,不仅增加了游戏的趣味性和挑战性,还让玩家在升级过程中有了更多的策略和选择。你可以根据自己的武器库和卷轴数量,制定出最合适的升级计划,从而在游戏中占据先机。

nmdbbzcl的博客 1236

文件操作【C语言】

C语言还不会文件的一些操作?赶紧进来!!!

wzh18907434168的博客 1354

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

C语言-文件操作函数大全

fopen` 函数用于打开一个文件,并返回一个指向该文件的指针。如果打开文件失败,`fopen` 会返回 `NULL`。```c```参数:- `path`: 要打开的文件的路径。- `mode`: 文件的打开模式(例如:`"r"` 读取模式,`"w"` 写入模式,`"a"` 追加模式等)。如果成功,返回一个指向 `FILE` 对象的指针。如果失败,返回 `NULL`。`fclose` 函数用于关闭由 `fopen` 函数打开的文件。

Jason_from_China的博客 2211

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

C语言,文件操作详解

在 C 语言中,文件操作的函数大多包含在 头文件中,使用时记得 #include。 一、打开和关闭文件 1. 打开文件 FILE * fopen ( const char * filename, const char * mode ); 打开一个文件,成功则返回文件的指针,失败则返回 NULL。 任何打开的文件在不需要使用后都必须关闭。 模式: r 打开只读文件,文件必须存在 ...

阿飞的博客 1万+

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

C语言中的文件操作

大家号,今天和大家说一说C语言中的文件操作。 在电脑的硬件中有外存和内存之分,外存通常很大,也就是我们常说的磁盘,今天所说的文件就是存储在外存中的。有时在C程序运行过程中,产生的数据我们想永久的保存在电脑中,而不是运行结束后数据就丢失了,比如我们写一个通讯录的程序,程序运行结束后我们想把通讯录中的数据保存下来,以便下次运行程序时可以找到这些数据。而由于外存的访问速度很慢,所以运行程序时数据都是在存储在内存中的(CPU访问内存的速度要比外存快很多),但运行结束后内存就还给了操作系统,使得数据无法永久保存,这

m0_62797154的博客 2043

c语言文件操作函数

文件操作函数

qq_42027094的博客 6308

【C语言】 C语言文件操作

本文介绍了C语言文件操作的核心概念与常用方法,主要包括: 文件类型:分为程序文件和数据文件; 文件操作流程:通过fopen/fclose打开关闭文件,使用文件指针FILE*进行操作; 读写方法:详细讲解了字符级读写(fputc/fgetc)、格式化读写(fprintf/fscanf)和二进制读写(fwrite/fread)三种方式,并提供了完整示例代码。文章还特别强调了文件打开模式的选择和错误检查的重要性,为文件操作提供了实用指导。

a_sen的博客 1680
上一篇: 动态内存分配
下一篇: C语言小项目——通讯录
岸边露伴'
博客等级 码龄3年 2粉丝 20原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值