C语言笔记23 •文件操作•

1.为什么要使用文件?

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

2.什么是文件?

计算机磁盘(硬盘)上的⽂件就是⽂件。
但是在程序设计中,我们⼀般谈的⽂件有两种:程序文件、数据文件(从⽂件功能的⻆度来分类
的)。
程序文件:就是该文件里的内容在计算机的编译器中可以进行运行,笼统的可以理解为文件内容是计算机语言,C语言文件以.c结尾,python语言文件以.py结尾等等。
程序文件包括源程序文件(后缀为.c) ,目标文件(windows环境后缀为.obj) ,可执行程序(windows环境后缀为.exe)。
数据文件:文件内容一般不是程序,而是一般的文本数据,比如word文件(.doc/.docx)、文本文件(.txt)

3.流和标准流

:程序的数据需要输出到各种外部设备,也需要从外部设备获取数据,所以中间就需要一个中间桥梁来输送它们之间的关系, 所以就把这种关系称作“流”,可以想象流淌着字符数据的河流。
C语言对文本的输入输出(读写)、画面、键盘都需要“流”来进行操作。向“流”里写入数据,还是从“流”里读取数据,需要以某种方式打开“流”,才能对数据进行操作。
标准流: 标准输入流(键盘 stdin),标准输出流(屏幕 stdout),标准错误流( stderr
stdin、stdout、stderr 三个流的类型是: FILE * ,通常称为⽂件指针。 C语⾔中,就是通过 FILE* 的⽂件指针来维护流的各种操作的。

4.文件指针

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

VS2013 编译环境提供的 stdio.h 头⽂件中有以下的⽂件类型(FILE)的声明:

struct _ iobuf
{
   char *_ptr;
   int _cnt;
   char *_base;
  int _flag;
  int _file;
  int _charbuf;
  int _bufsiz;
  char *_tmpfname;
};
typedef struct _ iobuf FILE ;//对  struct _ iobuf 重命名为 FILE
//不同的C编译器的FILE类型包含的内容不完全相同,但是大同小异。
⼀般都是通过⼀个FILE的指针来维护这个FILE结构的变量,这样使⽤起来更加⽅便。
FILE* pf; // ⽂件指针变量
//使pf指向某个⽂件的⽂件信息区(是⼀个结构体变量), 通过⽂件指针变量能够间接找到与
它关联的⽂件。可以看下图所示:

5.文件的打开方式

#include <stdio.h>

//在txt文件里写入字符串
int main()
{
	FILE* pr = fopen(".\\test.txt", "w");
	if (pr == NULL)
	{
		perror("fopen");
		return 1;
	}
	//写文件
	fputs("Hello!\n", pr);
	fputs("I am a boy.", pr);

	//关闭文件
	fclose(pr);
	pr = NULL;

	return 0;
}

6.文件的顺序读写函数介绍

fgetc:读取文件中单个字符,可以换行读取,用于“r”  :            

 int fgetc ( FILE * stream );

fputc:将字符串中单个字符,写到文件中,每次只能写一个,可以hun'H'n,用于“w” :

int fputc ( int character, FILE * stream );

fgets:读取文件中字符串,写在数组中,不可以换行读取,用于“r” :

char * fgets ( char * str, int num, FILE * stream );

fputs:将字符串,写在文件中,用于“w”  :

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

fscanf:格式化输入函数,从文件中读取信息,存放到结构体的各个成员中,用于“r”

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

fprintf:格式化输出函数,把结构体的信息写在文件里,用于“w”

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

fread:读取二进制文件中的信息放在结构体中,用于"rb":

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

fwrite:以二进制形式写在文件中,用于"wb":

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

对应的代码看10.代码附录

7.⽂件的随机读写函数介绍

fseek 根据⽂件指针的位置和偏移量来定位⽂件指针,来读取文件中的内容。
int fseek ( FILE * stream, long int offset, int origin ); 
fseek的第三个参数(int origin)有三种模式:
SEEK_SET文件开头
SEEK_CUR文件指针的当前位置
SEEK_END文件末尾 
ftell :返回⽂件指针相对于起始位置的偏移量
long int ftell ( FILE * stream );
rewind:让⽂件指针的位置回到⽂件的起始位置
void rewind ( FILE * stream );
对应的代码看 10.代码附录

 8.文件读取结束的判定

feof:在⽂件读取过程中,不能⽤feof函数的返回值直接来判断⽂件的是否结束。当⽂件读取结束的时候,判断是读取结束的原因是否是:遇到⽂件尾结束。

int feof ( FILE * stream );

在vs2022中feof遇到结束标志EOF/NULL返回1,没遇到返回0,但是如果文件为空文件的话,则返回0,这也是文件末尾,就不能及时检测。

ferror:判断文件读取过程中是否出现错误,与feof返回值相反  读取完毕 返回0  未读取完,返回1。

int ferror ( FILE * stream );

对应的代码看10.代码附录

9.文件缓冲区

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

10.代码附录

//1.在txt文件里写入字符串
int main()
{
	FILE* pr = fopen(".\\test.txt", "w");
	if (pr == NULL)
	{
		perror("fopen");
		return 1;
	}
	//写文件
	fputs("Hello!\n", pr);
	fputs("I am a boy.", pr);

	//关闭文件
	fclose(pr);
	pr = NULL;

	return 0;
}
//2.从txt文件里读字符串
int main()
{
	FILE* pr = fopen(".\\test.txt", "r");
	if (pr == NULL)
	{
		perror("fopen");
		return 1;
	}
	char str[20] = "xxxxxxxxx";
	//读文件
	fgets(str, 6, pr);
	
	printf("%s", str);
	
	//关闭文件
	fclose(pr);
	pr = NULL;

	return 0;
}
3.从键盘上读字符串  写在屏幕上
int main()
{
	char str[20] = "xxxxxxxxx";

	fgets(str, 20, stdin);//从键盘(标准输入流stdin)上读取字符串   //文本行输入函数
	fputs(str, stdout);将字符串写在屏幕(标准输出流stdout)上   //文本行输出函数

	return 0;
}
//4.把结构体的信息写在文件里
struct S
{
	char name[20];
	int age;
	float store;
};
int main()
{
	FILE* pr = fopen("test.txt", "w");
	if (pr == NULL)
	{
		perror("fopen");
		return 1;
	}
	struct S s = { "zhangsan",20,88.2f };
	//写文件
	fprintf(pr,"%s %d %.1f",s.name,s.age,s.store);//格式化输出函数

	printf("%s %d %.1f", s.name, s.age, s.store);

	//关闭文件
	fclose(pr);
	pr = NULL;

	return 0;
}
//5.从文件中读取信息,存放到结构体的各个成员中
struct S
{
	char name[20];
	int age;
	float score;
};
int main()
{
	//打开文件
	FILE* pr = fopen("test.txt", "r");
	if (pr == NULL)
	{
		perror("fopen");
		return 1;
	}
	struct S s = {0};

	//读文件
	fscanf(pr, "%s %d %f", s.name, &(s.age), &(s.score));

	//打印到屏幕上
	//printf("%s %d %.1f", s.name, s.age, s.score);
	fprintf(stdout,"%s %d %.1f", s.name, s.age, s.score);
	
	//关闭文件
	fclose(pr);
	pr = NULL;

	return 0;
}
//6.非文件操作函数  sscanf  sprintf 
struct S
{
	char name[20];
	int age;
	float score;
};
int main()
{
	char arr[100] = { 0 };
	struct S s = { "zhangnan",20,88.2f };

	sprintf(arr, "%s %d %.1f", s.name, s.age, s.score);//将结构体s中的各个成员数据转化为字符串存放在arr中
	printf("%s\n", arr);

	struct S t = {0};//创建结构体变量 t 

	sscanf(arr, "%s %d %f", t.name, &(t.age), &(t.score));//将arr中的数据 提取为格式化数据  存放在结构体 t 中
	printf("%s %d %.1f", t.name, t.age, t.score);

	return 0;
}

//7.以二进制形式写在文件中
struct S
{
	char name[20];
	int age;
	float store;
};
int main()
{
	//打开文件
	FILE* pr = fopen("test.txt", "wb");
	if (pr == NULL)
	{
		perror("fopen");
		return 1;
	}
	struct S s = { "zhangsan",30,88.5f };
	//写文件
	fwrite(&s,sizeof(struct S),1,pr);//以二进制形式写在文件中

	printf("%s %d %.1f", s.name, s.age, s.store);

	//关闭文件
	fclose(pr);
	pr = NULL;

	return 0;
}

//8.读取二进制的信息写在文件中
struct S
{
	char name[20];
	int age;
	float store;
};
int main()
{
	//打开文件
	struct S w = {0};
	FILE* pr = fopen("test.txt", "rb");
	if (pr == NULL)
	{
		perror("fopen");
		return 1;
	}
	
	//读文件
	printf("%s %d %.1f\n", w.name, w.age, w.store);

	fread(&w, sizeof(struct S), 1, pr);//读取二进制文件中的信息写在结构体中
	Sleep(1000);//延迟1s

	printf("%s %d %.1f", w.name, w.age, w.store);

	//关闭文件
	fclose(pr);
	pr = NULL;

	return 0;
}

//9.文件的随机读写
int main()
{
	//打开文件

	FILE* pr = fopen("test.txt", "r");
	if (pr == NULL)
	{
		perror("fopen");
		return 1;
	}

	//读文件
	int ch = 0;
	ch = fgetc(pr);
	printf("%c\n", ch);//a
	ch = fgetc(pr);
	printf("%c\n", ch);//b

	//定位指针文件
	//fseek(pr, 4, SEEK_SET);//(文件开头)相对于起始位置的偏移量 
	//ch = fgetc(pr);
	//printf("%c\n", ch);//e

	//fseek(pr, 2, SEEK_CUR);//(文件指针的当前位置)相对于当前位置的偏移量 
	//ch = fgetc(pr);
	//printf("%c\n", ch);//e

	fseek(pr, -2, SEEK_END);//(文件末尾位置)相对于当前位置的偏移量 
	ch = fgetc(pr);
	printf("%c\n", ch);//e  

	printf("%d\n", ftell(pr));//输出文件指针相较于文件的起始位置的偏移量  abcdef

	rewind(pr);//将文件指针重新定位到文件的起始位置
	ch = fgetc(pr);
	printf("%c\n", ch);

	//关闭文件
	fclose(pr);
	pr = NULL;

	return 0;
}

//10.拷贝文件将test.txt内容拷贝到  test1.txt
int main()
{
	//打开文件

	FILE* pr = fopen("test.txt", "r");
	if (pr == NULL)
	{
		perror("fopen\n");
		return 1;
	}

	FILE* pr1 = fopen("test1.txt", "w");
	if (pr == NULL)
	{
		perror("fopen");
		fclose(pr);
		pr = NULL;
		return 1;
	}

	//拷贝文件开始
	int ch = 0;
	while ((ch = fgetc(pr)) != EOF)
	{
		fputc(ch, pr1);
	}//拷贝结束
	printf("拷贝结束\n");
	//关闭文件
	fclose(pr);
	pr = NULL;
	
	fclose(pr1);
	pr1 = NULL;
	return 0;
}

//11.文件读取结束判断函数(feof 读取完毕 返回1  、未读取完 返回0)
int main()
{
	打开文件
	FILE* pr = fopen("test.txt", "r");
	if (pr == NULL)
	{
		perror("fopen\n");
		return 1;
	} 
	int ch = 0;
	ch = fgetc(pr);
	printf("%d\n", feof(pr));  //未读取完 返回0
	while ((ch = fgetc(pr)) != EOF)
	{
		printf("%c\n",ch);
		printf("%d\n", feof(pr));//未读取完 返回0
	}

	printf("===================================\n");

	printf("%d\n", feof(pr));  //读取完毕 返回1


	判断是什么造成的文件读取结束
	if (feof(pr))  //读取完毕 返回1  未读取完 返回0
	{
		printf("feof:文件内容读取完\n");
		return 1;
	}
	else if (ferror(pr))  //与feof返回值相反  读取完毕 返回0  未读取完 返回1
	{
		printf("ferror:文件读取过程中出现错误\n");
		return -1;
	}

	关闭文件
	fclose(pr);
	pr = NULL;

	return 0;
}

//12.文件缓冲区(文件拷贝查看缓冲区现象)
int main()
{
	FILE* p = fopen("test.txt", "w");
	fputs("abcdef", p);//将字符串 abcdef. 写入 p→test.txt
	printf("睡眠10秒-已经写数据了,打开test.txt文件,发现文件没有内容\n");
    Sleep(10000);
    printf("刷新缓冲区\n");
    fflush(p);//刷新缓冲区时,才将输出缓冲区的数据写到文件(磁盘)
    //注:fflush 在高版本的VS上不能使用了
    printf("再睡眠10秒-此时,再次打开test.txt文件,文件有内容了\n");
    Sleep(10000);

    fclose(p);//注:fclose在关闭文件的时候,也会刷新缓冲区
    p = NULL;

	return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

视频如何转换成音频?音视频转换,4个方法

在当今数字化时代&#xff0c;我们常常需要处理各种不同格式的音视频文件。可能您有一个视频文件&#xff0c;但是您需要它的音频部分&#xff0c;或者您有一个音频文件&#xff0c;但您希望将其转换为视频格式。 无论您的需求是什么&#xff0c;音视频转换已经成为我们数字生…

人脸识别系统之动态人脸识别

二&#xff0e;动态人脸识别 1.摄像头人脸识别 1.1.导入资源包 import dlib import cv2 import face_recognition from PIL import Image, ImageTk import tkinter as tk import os注&#xff1a;这些导入语句允许您在代码中使用这些库和模块提供的功能&#xff0c;例如创建…

联邦学习数据集划分Dirichlet划分法及其可视化

文章目录 前言图片效果&#xff1a;独立同分布效果非独立同分布效果 一、参数输入输出 二、代码可视化:标签划分&#xff1a;代码调用 前言 用于实现并控制联邦学习客户端之间数据集非独立同分布&#xff0c;并将效果可视化 图片效果&#xff1a; 独立同分布效果 对不同类别…

python中的循环控制语句break与continue

学习这两个语句之前&#xff0c;我们要先了解这两个语句是什么意思&#xff1a; break&#xff1a;中断、打破的意思。所以它的跳出循环的意思 continue&#xff1a;继续的意思&#xff0c;意思是跳过当前条件&#xff0c;继续循环 新需求来了&#xff01;我们不仅要告诉 Py…

运营干货:用户运营体系

1、用户生命周期 2、用户引入阶段 3、用户留存阶段 4、用户回流阶段

Camunda BPM架构

Camunda BPM既可以单独作为流程引擎服务存在,也能嵌入到其他java应用中。Camunda BPM的核心流程引擎是一个轻量级的模块,可以被Spring管理或者加入到自定义的编程模型中,并且支持线程模型。 1,流程引擎架构 流程引擎由多个组件构成,如下所示: API服务 API服务,允许ja…

创意KMS知识图谱ui设计合集来了

创意KMS知识图谱ui设计合集来了

Redis的一致性

一、产生的原因 使用缓存&#xff0c;在进行写操作的时候就会出现不一致的问题。 一致性分为三类&#xff1a;强一致性&#xff0c;弱一致性&#xff0c;最终一致性 二、方案 2.1 延时双删 在更新数据库的操作前后分别进行一次删除缓存的操作&#xff0c;并在更新数据库之后…

广工电工与电子技术实验报告-按键键值识别和LED数码管显示

实验代码 Key_LED.v module Key_LED (key, HEX0); input[3:0] key; output[6:0] HEX0; reg[3:0] A; always (key) begin if (key[0] < 0) begin A 4b0001; end else if (key[1] < 0) begin A 4b0010; end else if (key[2] < 0) begin A 4b0011; end else if (key[…

Java——分支语句

控制结构是管理代码执行流程的基础。主要包括顺序控制、分支控制和循环控制。 一、顺序控制 顺序控制是最基本的控制结构&#xff0c;程序按照代码的书写顺序逐行执行。 public class SequentialControl {public static void main(String[] args) {int a 5;int b 10;int s…

jupyter notebook使用conda环境

pycharm中安装过可以使用的库在jupyter notebook中导入不进来 1 检查pycharm中安装的库的位置 2 检查jupyter notebook中安装的库的位置 3 查看jupyter notebook内核名字 可以看到jupyter notebook中内核名字叫ipykernel 4 安装ipykernel 在pycharm的terminal中 pip instal…

微服务:Rabbitmq利用jackson序列化消息为Json发送并接收

消息序列化 Spring默认会把你发送的消息通过JDK序列化为字节发送给MQ&#xff0c;接收消息的时候&#xff0c;再把字节反序列化为Java对象。 我们可以配置JSON方式来序列化&#xff0c;这样体积更小&#xff0c;可读性更高。 引入依赖&#xff1a; <dependency><g…

CV每日论文---2024.6.3

1、Video-MME: The First-Ever Comprehensive Evaluation Benchmark of Multi-modal LLMs in Video Analysis 中文标题&#xff1a;Video-MME&#xff1a;视频分析领域首个多模态法学硕士综合评估基准 简介&#xff1a;Video-MME 是一个全面评估多模态大语言模型&#xff08;M…

18、Go Gin框架中的binding验证器使用

一、binding功能介绍 Gin的binding包提供了一组功能&#xff0c;用于将请求的数据自动绑定到结构体&#xff0c;并根据结构体标签进行数据验证。常用的标签有binding和validate&#xff0c;通过这些标签可以指定数据的类型和验证规则。 常见标签 binding:"required"…

今日好料推荐(运维服务管理流程+互联网运维)

今日好料推荐&#xff08;运维服务管理流程互联网运维&#xff09; 本文内容是运维服务管理的梳理 参考资料内容&#xff1a;运维服务管理流程设计&互联网运维理论与实践 参考资料在文末获取&#xff0c;关注我&#xff0c;分享优质前沿资料&#xff08;IT、运维、编码、…

斜拉桥智慧施工数字孪生

基于图扑自主研发的 HT for Web 产品&#xff0c;利用现场照片及 CAD 图纸&#xff0c;结合 PBR 材质&#xff0c;搭建了具有赛博朋克风格的智慧斜拉桥可视化解决方案&#xff0c;精准复现斜拉桥建造规划过程&#xff0c;辅助运维人员对桥梁基建过程的网格化管理。提高桥梁的建…

【Spring Cloud Alibaba】Nacos统一配置管理

目录 回顾问题 统一配置管理配置中心的解决方案&#xff1a;Nacos的关键特性动态配置服务小结 Nacos的架构 Spring Cloud Alibaba Nacos Config1.创建项目2.添加依赖3.添加启动注解4.添加配置信息5.使用控制器类动态读取配置信息6.Nacos Server添加配置信息7.测试 Nacos Namesp…

大疆、西圣、枫笛领夹麦哪个好?大疆、西圣领夹麦克风测评对比

不知道大家有没有想过一个问题&#xff0c;为什么有些视频或直播的声音听起来那么清晰&#xff0c;仿佛身临其境&#xff1f;其实最主要的就是麦克风的原因&#xff0c;我们以前用的麦克风或多或少都会存在一些小毛病例如&#xff1a;音质不清晰、传输不稳定容易断断续续、声音…

国内PLM系统厂商,国内PLM系统哪个公司最受欢迎

国内PLM系统厂商,国内PLM系统哪个公司最受欢迎 国内PLM系统厂商中&#xff0c;要确定哪个公司的产品最受欢迎&#xff0c;需要考虑多个因素&#xff0c;包括市场份额、客户评价、技术实力、产品线完整性以及服务支持等。虽然无法直接给出一个具体的“最受欢迎”的排名&#xff…

centos7安装kubernetes v1.28.2

centos7安装kubernetes v1.28.2 一&#xff0e;环境部署 1.1基础环境配置 主机IP 主机名规划 172.17.48.15 master 172.17.48.3 node1 1.2修改机器名称 #永久修改主机名 hostnamectl set-hostname master && bash #在master上操作 hostnamectl set-hostname …