C语言:深入理解文件操作

目录

[1. 为什么使用文件?](#1. 为什么使用文件?)

[2. 什么是文件?](#2. 什么是文件?)

[2.1 程序文件](#2.1 程序文件)

[2.2 数据文件](#2.2 数据文件)

[2.3 文件名](#2.3 文件名)

[3. 二进制文件和文本文件?](#3. 二进制文件和文本文件?)

3.1测试代码:

[4. 文件的打开和关闭](#4. 文件的打开和关闭)

[4.1 流和标准流](#4.1 流和标准流)

[4.1.1 流](#4.1.1 流)

[4.1.2 标准流](#4.1.2 标准流)

[4.2 文件指针](#4.2 文件指针)

[4.3 文件的打开和关闭](#4.3 文件的打开和关闭)

[5. 文件的顺序读写](#5. 文件的顺序读写)

[5.1 顺序读写函数介绍](#5.1 顺序读写函数介绍)

fgetc函数使用

fputc函数使用

fgets函数使用

fputs函数使用

fscanf函数使用

fprintf函数使用

fread函数使用

fwrite函数使用

5.2与字符串有关联的两个函数:

sscanf函数使用

sprintf函数使用

6.文件的随机读写

6.1fseek

6.2ftell

6.3rewind

7.文件读取结束的判定

[7.1 ferror及被错误使用的 feof](#7.1 ferror及被错误使用的 feof)

8.文件缓冲区

9.完整的文件操作练习源码及运行结果


1. 为什么使用文件?

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

2. 什么是文件?

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

2.1 程序文件

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

2.2 数据文件

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

平常的写代码时所处理数据的输⼊输出都是以终端为对象的,即从终端的键盘输⼊数据,运⾏结果显⽰到 显⽰器上。 其实有时候我们会把信息输出到磁盘上,当需要的时候再从磁盘上把数据读取到内存中使⽤,这⾥处 理的就是磁盘上⽂件。

2.3 文件名

⼀个⽂件要有⼀个唯⼀的⽂件标识,以便⽤⼾识别和引⽤。 文件名包含3部分:文件路径+文件名主干+文件后缀 例如: c:\code\test.txt

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

3. 二进制文件和文本文件?

根据数据的组织形式,数据文件被称为文本文件或者二进制文件。 数据在内存中以二进制的形式存储,如果不加转换的输出到外存的文件中,就是二进制文件。 如果要求在外存上以ASCII码的形式存储,则需要在存储前转换。以ASCII字符的形式存储的文件就是文本文件。 ⼀个数据在文件中是怎么存储的呢? 字符⼀律以ASCII形式存储,数值型数据既可以⽤ASCII形式存储,也可以使⽤二进制形式存储。 如有整数10000,如果以ASCII码的形式输出到磁盘,则磁盘中占用5个字节(每个字符⼀个字节),而二进制形式输出,则在磁盘上只占4个字节(VS2022测试)。

3.1测试代码:

cpp 复制代码
int main()
{
	int a = 10000;
	FILE * pf = fopen("test100.txt", "wb");
	fwrite(&a, 4, 1, pf);//⼆进制的形式写到⽂件中 
	fclose(pf);
	pf = NULL;
	return 0;
}

运行代码之后我们单击

打开文件

由于这是一个二进制文件不支持打开,那么我们把它添加进来

添加现有项:

单击二进制编辑器

4. 文件的打开和关闭

4.1 流和标准流

4.1.1 流

我们程序的数据需要输出到各种外部设备,也需要从外部设备获取数据,不同的外部设备的输⼊输出 操作各不相同,为了⽅便程序员对各种设备进⾏⽅便的操作,我们抽象出了流的概念,我们可以把流 想象成流淌着字符的河。 C程序针对⽂件、画⾯、键盘等的数据输⼊输出操作都是通过流操作的。 ⼀般情况下,我们要想向流⾥写数据,或者从流中读取数据,都是要打开流,然后操作。

4.1.2 标准流

那为什么我们从键盘输⼊数据,向屏幕上输出数据,并没有打开流呢? 那是因为C语⾔程序在启动的时候,默认打开了3个流:

stdin标准输入流,在⼤多数的环境中从键盘输⼊,scanf函数就是从标准输⼊流中读取数据。

stdout标准输出流,⼤多数的环境中输出⾄显⽰器界⾯,printf函数就是将信息输出到标准输出 流中。

stderr标准错误流,⼤多数环境中输出到显⽰器界⾯。 这是默认打开了这三个流,我们使⽤scanf、printf等函数就可以直接进⾏输⼊输出操作的。stdin、stdout、stderr三个流的类型是: FILE * ,通常称为⽂件指针。 C语⾔中,就是通过 FILE* 的⽂件指针来维护流的各种操作的。

4.2 文件指针

缓冲⽂件系统中,关键的概念是"⽂件类型指针",简称"⽂件指针"。 每个被使⽤的⽂件都在内存中开辟了⼀个相应的⽂件信息区,⽤来存放⽂件的相关信息(如⽂件的名 字,⽂件状态及⽂件当前的位置等)。这些信息是保存在⼀个结构体变量中的。该结构体类型是由系 统声明的,取名FILE. 例如,VS2013编译环境提供的 stdio.h 头⽂件中有以下的⽂件类型声明:

cpp 复制代码
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*的指针变量:

cpp 复制代码
FILE* pf;//⽂件指针变量

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

4.3 文件的打开和关闭

⽂件在读写之前应该先打开文件,在使⽤结束之后应该关闭⽂件。 在编写程序的时候,在打开⽂件的同时,都会返回⼀个FILE*的指针变量指向该⽂件,也相当于建⽴了指针和文件的关系。 ANSIC规定使⽤ fopen 函数来打开⽂件, fclose 来关闭⽂件。

cpp 复制代码
//打开⽂件 
FILE * fopen ( const char * filename, const char * mode );

//关闭⽂件 

int fclose ( FILE * stream );

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

实例代码:

cpp 复制代码
/* 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;
}

5. 文件的顺序读写

5.1 顺序读写函数介绍

上⾯说的适⽤于所有输⼊流⼀般指适⽤于标准输⼊流和其他输⼊流(如⽂件输⼊流);所有输出流⼀ 般指适⽤于标准输出流和其他输出流(如⽂件输出流)。

fgetc函数使用

cpp 复制代码
int fgetc ( FILE * stream );

参数:

stream:指向标识输入流的 FILE 对象的指针。

cpp 复制代码
//fgetc读
	FILE* pfr = fopen("test.txt", "r");
	if (pfr == NULL)
	{
		perror("fopen pfr test.txt fail!");
		return 1;
	}
	int chr = 0;
	while ((chr = fgetc(pfr)) != EOF)
	{
		printf("%c ", chr);
	}
	fclose(pfr);
	pfr = NULL;

从流中一个字符一个字符读取,读取成功后返回该字符的ASCII码值,直到读取到最后一个字符返回EOF(-1)

fputc函数使用

cpp 复制代码
int fputc ( int character, FILE * stream );

参数:

character:要编写的字符的 整型类型。
写入时,该值在内部转换为无符号字符。

stream:指向标识输出流的 FILE 对象的指针。

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
//fputc写
	FILE* pfw = fopen("test.txt", "w");
	if (pfw == NULL)
	{
		perror("fopen pfw test.txt fail!");
		return 1;
	}
	int chw = 0;
	for (chw = 'a'; chw <= 'z'; chw++)
	{
		printf("%c ", chw);
		fputc(chw, pfw);
	}
	fclose(pfw);
	pfw = NULL;
   


   return 0;
}

将a-z26个字符一个一个写入流中

fgets函数使用

cpp 复制代码
char * fgets ( char * str, int num, FILE * stream );

参数:

str:

指向复制字符串读取的 char数组的指针。

num:

要复制到 str 中的最大字符数(包括终止 null 字符)。

stream:

指向标识输入流的 FILE 对象的指针。
stdin 可以用作从标准输入读取的参数。

cpp 复制代码
//fgets读
FILE* pfr2 = fopen("test1.txt", "r");
if (pfr2 == NULL)
{
	perror("fopen pfr2 test1.txt fail");
	return 1;
}
char arr[50] = { 0 };
fgets(arr, 19, pfr2);
printf("%s", arr);
fclose(pfr2);
pfr2 = NULL;

把流中的字符串中的18个字符读过来,最后赋一个'\0',所以这里注意,19的含义

fputs函数使用

cpp 复制代码
int fputs ( const char * str, FILE * stream );

参数:

str:

包含要写入 的内容的 C 字符串

stream:

指向标识输出流的 FILE 对象的指针。

cpp 复制代码
	//fputs写
	FILE* pfw2 = fopen("test1.txt", "w");
	if (pfw2 == NULL)
	{
		perror("fopen pfw2 test1.txt fail!");
		return 1;
	}
	char Array[50] = { "这是一个字符串" };
	printf("%s",Array);
	fputs(Array, pfw2);
	fclose(pfw2);
	pfw2 = NULL;

将一个字符串写入流中

fscanf函数使用

cpp 复制代码
int fscanf ( FILE * stream, const char * format, ... );

参数:

stream:

指向 FILE 对象的指针,该对象标识要从中读取数据的输入流。

format:格式(和scanf函数一样)...

cpp 复制代码
//fscanf读
FILE* pfr3 = fopen("test2.txt", "r");
if (pfr3 == NULL)
{
	perror("fopen pfr3 test2.txt fail");
	return 1;
}
int array[19] = { 0 };
for (i = 0; i < sizeof(array) / sizeof(array[0]); i++)
{
	fscanf(pfr3, "%d", &array[i]);
	printf("%d ", array[i]);
}

fclose(pfr3);
pfr3 = NULL;

将格式化的数据从流中读取出来存放入array中

fprintf函数使用

cpp 复制代码
int fprintf ( FILE * stream, const char * format, ... );

参数:

stream:指向标识输出流的 FILE 对象的指针。

format:格式(和printf函数一样)...

cpp 复制代码
//fprintf写
FILE* pfw3 = fopen("test2.txt", "w");
if (pfw3 == NULL)
{
	perror("fopen pfw3 test2.txt fail");
	return 1;
}
int arr1[19] = { 1,2,3,4,5,6,7,8,9,10 };
int i = 0;
for (i = 0; i < sizeof(arr1) / sizeof(arr1[0]); i++)
{
	printf("%d ", arr1[i]);
	fprintf(pfw3, "%d ", arr1[i]);
}
fclose(pfw3);
pfw3 = NULL;

将格式化的数据写入流中

fread函数使用

cpp 复制代码
size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );

参数:

ptr:

指向大小至少为 (size*count) 字节的内存块的指针,该内存块已转换为 void*。

size:

要读取的每个元素的大小(以字节为单位)。
size_t 是无符号整数类型。

count:

元素的数量,每个元素的大小为 bytes
size_t 是无符号整数类型。

stream:

指向指定输入流的 FILE 对象的指针。

cpp 复制代码
//fread读取二进制文本
FILE* wrpf = fopen("binary.txt", "rb");
if (wrpf == NULL)
{
perror("fopen wrpf binary.txt fail");
return 1;
}
int rarr[11] = { 0 };
i = 0;
while (fread(&rarr[i], sizeof(int), 1, wrpf))
{
	printf("%d ", rarr[i++]);
}
fclose(wrpf);
wrpf = NULL;

把流中的二进制数据读取出来,然后格式化打印出可看懂的数据

fwrite函数使用

cpp 复制代码
size_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream );

参数:

ptr:

指向要写入的元素数组的指针,将其转换为 const void*。

size:

要写入的每个元素的大小(以字节为单位)。
size_t 是无符号整数类型。

count:

元素的数量,每个元素的大小为 bytes
size_t 是无符号整数类型。

stream:

指向指定输出流的 FILE 对象的指针。

cpp 复制代码
//fwrite二进制写入
FILE* wbpf = fopen("binary.txt","wb");
if (wbpf == NULL)
{
	perror("fopen wbpf binary.txt fail");
	return 1;
}

int warr[10] = { 1,2,3,4,5,6,7,8,9,10 };
fwrite(warr, sizeof(int), 5, wbpf);
fclose(wbpf);
wbpf = NULL;

将数据以二进制的形式写入流中

5.2与字符串有关联的两个函数:

sscanf函数使用

cpp 复制代码
int sscanf ( const char * s, const char * format, ...);

参数:

s:

函数作为其源处理以检索数据的 C 字符串。

format:

C 字符串,包含一个格式字符串,该字符串遵循与 scanf 中的格式 相同的规范(有关详细信息,请参阅 scanf)。

...(附加参数)

根据格式 字符串,该函数可能需要一系列附加参数,每个参数都包含指向已分配存储的指针,其中提取的字符的解释以适当的类型存储。
这些参数的数量至少应与格式说明符存储的值数一样多。该函数将忽略其他参数。

cpp 复制代码
//sscanf读
student s2 = { 0 };
sscanf(buf, "%s%d%s", s2.name, &(s2.age), s2.gender);
printf("以格式化形式打印s2:%s %d %s\n", s2.name, s2.age, s2.gender);

将字符串形式的数据,以格式化的形式读取出来让结构体s2接收

sprintf函数使用

cpp 复制代码
int sprintf ( char * str, const char * format, ... );

参数:

str

指向存储生成的 C 字符串的缓冲区的指针。
缓冲区应足够大,以包含生成的字符串。

格式

C 字符串,包含一个格式字符串,该字符串遵循与 printf 中的格式 相同的规范(有关详细信息,请参阅 printf)。

...(附加参数)

根据格式 字符串,该函数可能需要一系列附加参数,每个参数都包含一个值,用于替换格式 字符串中的格式说明符 (或指向存储位置的指针,对于 n)。
这些参数的数量至少应与格式说明符中指定的值数一样多。该函数将忽略其他参数。

cpp 复制代码
//sprintf写
FILE* swpf = fopen("text.txt3", "w");
if (swpf == NULL)
{
	perror("fopen swpf text.txt3 fail!");
	return 1;
}
student s1 = { "张三",19,"男" };
printf("以格式化形式打印s1:%s %d %s\n", s1.name, s1.age, s1.gender);
char buf[200] = { 0 };
sprintf(buf,"%s %d %s", s1.name, s1.age, s1.gender);
printf("以字符串形式打印s1:%s",buf);
fprintf(swpf,"%s ", buf);
fclose(swpf);
swpf = NULL;

将格式化形式的数据,转换成字符串形式的数据

6.文件的随机读写

6.1fseek

cpp 复制代码
int fseek ( FILE * stream, long int offset, int origin );

根据⽂件指针的位置和偏移量来定位⽂件指针(⽂件内容的光标)。

cpp 复制代码
//fseek随机读写
FILE* fseekpf = fopen("fseek.txt", "r");
if (fseekpf == NULL)
{
	perror("fopen fseekpf fseek.txt fail!");
	return 1;
}
fseek(fseekpf, 4, SEEK_SET);
int ch=fgetc(fseekpf);
printf("%c ",ch);

参数:

stream

指向标识流的 FILE 对象的指针。

offset

二进制文件:要从 偏移的字节数。
文本文件:零,或 ftell 返回的值。

origin

用作偏移 量参考的位置。它由 <cstdio> 中定义的以下常量之一指定,专门用作此函数的参数:

不断 参考位置
SEEK_SET 文件开头
SEEK_CUR 文件指针的当前位置
SEEK_END 文件结束 *

*允许库实现不能有意义地支持 SEEK_END(因此,使用它的代码没有真正的标准可移植性)。

6.2ftell

cpp 复制代码
long int ftell ( FILE * stream );

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

参数:

stream

指向标识流的 FILE 对象的指针。

cpp 复制代码
//ftell返回文件指针相对于起始位置的偏移量
printf("\n%d", ftell(fseekpf));

6.3rewind

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

参数:

stream

指向标识流的 FILE 对象的指针。

cpp 复制代码
//rewind 将文件指针指向初始位置
rewind(fseekpf);

7.文件读取结束的判定

7.1 ferror及被错误使用的 feof

cpp 复制代码
int ferror ( FILE * stream );
cpp 复制代码
int feof ( FILE * stream );

参数:

stream

指向标识流的 FILE 对象的指针。

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

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

1. ⽂本⽂件读取是否结束,判断返回值是否为 EOF ( fgetc ),或者 NULL ( fgets ) 例如:

fgetc 判断是否为 EOF .

fgets 判断返回值是否为 NULL .

2. ⼆进制⽂件的读取结束判断,判断返回值是否⼩于实际要读的个数。 例如:

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

example:

cpp 复制代码
#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);
}

8.文件缓冲区

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

cpp 复制代码
#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;
}

这⾥可以得出⼀个结论: 因为有缓冲区的存在,C语⾔在操作⽂件的时候,需要做刷新缓冲区或者在⽂件操作结束的时候关闭文件

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

9.完整的文件操作练习源码及运行结果

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
typedef struct student
{
	char name[20];
	int age;
	char gender[10];
}student;
int main()
{
//fputc写
	FILE* pfw = fopen("test.txt", "w");
	if (pfw == NULL)
	{
		perror("fopen pfw test.txt fail!");
		return 1;
	}
	int chw = 0;
	for (chw = 'a'; chw <= 'z'; chw++)
	{
		printf("%c ", chw);
		fputc(chw, pfw);
	}
	fclose(pfw);
	pfw = NULL;
//换行
	printf("\n");

//fgetc读
	FILE* pfr = fopen("test.txt", "r");
	if (pfr == NULL)
	{
		perror("fopen pfr test.txt fail!");
		return 1;
	}
	int chr = 0;
	while ((chr = fgetc(pfr)) != EOF)
	{
		printf("%c ", chr);
	}
	fclose(pfr);
	pfr = NULL;
//换行
	printf("\n");
	
	//fputs写
	FILE* pfw2 = fopen("test1.txt", "w");
	if (pfw2 == NULL)
	{
		perror("fopen pfw2 test1.txt fail!");
		return 1;
	}
	char Array[50] = { "这是一个字符串" };
	printf("%s",Array);
	fputs(Array, pfw2);
	fclose(pfw2);
	pfw2 = NULL;

	//换行
	printf("\n");

	//fgets读
	FILE* pfr2 = fopen("test1.txt", "r");
	if (pfr2 == NULL)
	{
		perror("fopen pfr2 test1.txt fail");
		return 1;
	}
	char arr[50] = { 0 };
	fgets(arr, 19, pfr2);
	printf("%s", arr);
	fclose(pfr2);
	pfr2 = NULL;

	//换行
	printf("\n");

	//fprintf写
	FILE* pfw3 = fopen("test2.txt", "w");
	if (pfw3 == NULL)
	{
		perror("fopen pfw3 test2.txt fail");
		return 1;
	}
	int arr1[19] = { 1,2,3,4,5,6,7,8,9,10 };
	int i = 0;
	for (i = 0; i < sizeof(arr1) / sizeof(arr1[0]); i++)
	{
		printf("%d ", arr1[i]);
		fprintf(pfw3, "%d ", arr1[i]);
	}
	fclose(pfw3);
	pfw3 = NULL;


	//换行
	printf("\n");
	
	
	//fscanf读
	FILE* pfr3 = fopen("test2.txt", "r");
	if (pfr3 == NULL)
	{
		perror("fopen pfr3 test2.txt fail");
		return 1;
	}
	int array[19] = { 0 };
	for (i = 0; i < sizeof(array) / sizeof(array[0]); i++)
	{
		fscanf(pfr3, "%d", &array[i]);
		printf("%d ", array[i]);
	}
	
	fclose(pfr3);
	pfr3 = NULL;



	//换行
	printf("\n");
	
	//sprintf写
	FILE* swpf = fopen("text.txt3", "w");
	if (swpf == NULL)
	{
		perror("fopen swpf text.txt3 fail!");
		return 1;
	}
	student s1 = { "张三",19,"男" };
	printf("以格式化形式打印s1:%s %d %s\n", s1.name, s1.age, s1.gender);
	char buf[200] = { 0 };
	sprintf(buf,"%s %d %s", s1.name, s1.age, s1.gender);
	printf("以字符串形式打印s1:%s",buf);
	fprintf(swpf,"%s ", buf);
	fclose(swpf);
	swpf = NULL;

	//换行
	printf("\n");

	//sscanf读
	student s2 = { 0 };
	sscanf(buf, "%s%d%s", s2.name, &(s2.age), s2.gender);
	printf("以格式化形式打印s2:%s %d %s\n", s2.name, s2.age, s2.gender);



	//换行
	printf("\n");
	//fwrite二进制写入
	FILE* wbpf = fopen("binary.txt","wb");
	if (wbpf == NULL)
	{
		perror("fopen wbpf binary.txt fail");
		return 1;
	}

	int warr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	fwrite(warr, sizeof(int), 5, wbpf);
	fclose(wbpf);
	wbpf = NULL;

	//fread读取二进制文本
	FILE* wrpf = fopen("binary.txt", "rb");
	if (wrpf == NULL)
	{
	perror("fopen wrpf binary.txt fail");
	return 1;
	}
	int rarr[11] = { 0 };
	i = 0;
	while (fread(&rarr[i], sizeof(int), 1, wrpf))
	{
		printf("%d ", rarr[i++]);
	}
	//换行
	printf("\n");
	//feof和ferror判断文件是否是读取正常结束或读取异常结束
	if (feof(wrpf))
	{
		printf("文件读取正常结束\n");
	}
	else if (ferror(wrpf))
	{
		printf("文件读取异常结束\n");

	}
	fclose(wrpf);
	wrpf = NULL;

	//换行
	printf("\n");

	//fseek随机读写
	FILE* fseekpf = fopen("fseek.txt", "r");
	if (fseekpf == NULL)
	{
		perror("fopen fseekpf fseek.txt fail!");
		return 1;
	}
	fseek(fseekpf, 4, SEEK_SET);
	int ch=fgetc(fseekpf);
	printf("%c ",ch);
	
	//ftell返回文件指针相对于起始位置的偏移量
	printf("\n%d", ftell(fseekpf));

	//rewind 将文件指针指向初始位置
	rewind(fseekpf);
	//ftell返回文件指针相对于起始位置的偏移量
	printf("\n%d", ftell(fseekpf));

	fclose(fseekpf);
	fseekpf = NULL;
	return 0;
}
相关推荐
浪里个浪的10244 小时前
C语言基础:条件语句与分支控制实例解析
c语言·开发语言
想拿大厂offer5 小时前
【数据结构】第八节:链式二叉树
c语言·数据结构
qincjun7 小时前
数据库第一章:库的操作
c语言·数据库·c++
Crossoads8 小时前
【数据结构】带你初步了解排序算法
c语言·开发语言·数据结构·算法·排序算法
baidu_3755288110 小时前
ubuntu20.04/22.04/24.04 docker 容器安装方法
linux·c语言·c++·嵌入式硬件
摆烂小白敲代码10 小时前
大一新生以此篇开启你的算法之路
c语言·数据结构·c++·人工智能·经验分享·算法
ZARD99611 小时前
C语言16--宏定义和关键字
c语言
Byyyi耀11 小时前
Ascend C算子开发(中级)—— 编写Sinh算子
c语言·开发语言
转调11 小时前
C语言-第九章:文件读写
c语言·开发语言
Navigator_Z11 小时前
LeetCode //C - 363. Max Sum of Rectangle No Larger Than K
c语言·算法·leetcode