【零基础C语言】文件操作

目录

 理解文件操作

 什么是文件

 程序文件

 数据文件

 文件名字

 二进制文件和文本文件

 文件的打开和关闭

 文件的打开和关闭操作

实验1,打开一个文件并且输入26个字母 

打开读取文件text.txt ,并且将它拷贝进text_cpy.txt 

使用 fputs 和 fgets 函数 

使用 fprintf函数和 fscanf 函数 

有关于流的概念

 使用 fwrite 和 fread 函数

文件的随机读写 - 适用于二进制文件

 fseek 函数

ftell 函数 

 rewind 函数

 文件读取结束的判定

文件缓冲区


 

 理解文件操作

 我们为什么要使用文件呢?

 1.可以长久的存储我们的数据,没有文件存储我们输入的程序代码数据是在电脑内存中存储的,但是程序结束后,我们的数据也会清空,无法持久化保存

如以下代码:

int main()
{
	int a = 0; //创建变量a
	scanf("%d", &a); // 向a中输入数值
	return 0;
}

 我们可以通过内存窗口看见int变量a中存放我们输入的值,但是程序结束,数据会清空,我们需要重新输入

 什么是文件

 文件指的就是磁盘上的文件
 但是程序中我们的文件分为两种:程序文件,数据文件 - 按照功能划分

 

 程序文件


 struct 程序文件
{
    1.源程序文件(后缀为.c);
  2.目标文件(windows环境后缀为.obj);
  3.可执行文件(windows环境后缀为.exe);
};

 数据文件


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


 文件名字


 用于用户识别和使用,是文件的标识,这个相信大家都不陌生,我们在打开磁盘可以在上方的小方块看到当期文件的名字。

 二进制文件和文本文件

根据数据不同形式,我们将数据文件划分为二进制文件和文本文件

二进制文件:以二进制的形式存储,不用转换直接可以输出到外存

文本文件:字符一律以ASCLL码值存储,需要转换才可以输出到外存
 

 文件的打开和关闭

 在了解文件之前,我们需要认识一种抽象的概念 - 流
 什么是流呢?我们在生活中获取消息是从人流,网上等等渠道,同理计算机也是如此,
 我们把从键盘输入,文件读写和其他所有外部的数据糅合起来比作一条流淌着字符的数据河,
 而计算机则是从河中获取所需要的数据,读取它们,然后打开,再操作数据

 那么我们有可能有疑问了?我们平时键盘输入代码,屏幕打印字符数据好像并没有使用流啊
 这里我们就需要引入一个概念 - 标准流


 标准流在计算机C程序运行启动时就默认打开了3个流:

  1. stdin  - 标准输入流,获取我们输入的信息。
  2. stdout - 标准输出流,输出我们需要打印的信息
  3. stderr - 标准错误流。

 有了以上默认打开的流,我们使用scanf和printf就可以进行输入输出操作

 stdin,stdout,stderr 类型为 FILE* - 文件指针
 C语⾔中,就是通过FILE*的⽂件指针来维护流的各种操作的。

 文件指针

 我们在打开使用文件时,内存中会开辟一个文件信息区,这个信息区用来存放文件的相关
 信息,这些信息是保存在一个结构体变量中,取名为FILE。

 如vs2013编译环境中#include <stdio.h> 头文件种的类型申明。

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

 借助这点我们可以定义一个指针变量指向该文件信息区,间接的找到该文件

 FILE* pf; 文件指针变量


 文件的打开和关闭操作

 在读写编辑文件之前,我们需要学会如何打开和关闭文件

 1.打开文件

 在编写程序时在打开⽂件的同时,都会返回⼀个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+"(读写)- 打开一个二进制文本文件,在文件末尾进行读写 - 如果文件不存在(创建一个新的文件)
int main()
{
	// 创建文本指针变量
	FILE* pf;
	//打开文件
	pf = fopen("text.txt", "r");
	//文件操作
	if (pf == NULL)
	{
		//...
		perror("fopen");
		return 1;
	}
	else
	{
		fclose(pf);
		pf = NULL;
	}
	return 0;
}
 文件的顺序读写

 1.顺序读写函数介绍

  函数    功能          适用于

 fgetc - 字符输入函数 - 所有的输入流

 fputc - 字符输出函数 - 所有的输出流

 fgets - 文本行输入函数 - 所有输入流

 fputs - 文本行输入函数 - 所有输入流

 fscnaf - 格式化输入函数 - 所有输入流

 fprintf - 格式化输出函数 - 所有输出流

 fread   -   二进制输入   -   文件

 fwrite   -   二进制输出   -   文件

实验1,打开一个文件并且输入26个字母 

// 实验1,打开一个文件并且输入26个字母

int main()
{
	// 打开并且写一个文件 - "w"
	FILE* pf = fopen("text.txt", "w");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}

	//写文件
	int ch = 0;
	for (ch = 'a'; ch <= 'z'; ch++)
	{
		fputc(ch, pf);
	}

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

打开读取文件text.txt ,并且将它拷贝进text_cpy.txt 

// 打开读取文件text.txt ,并且将它拷贝进text_cpy.txt

int main()
{
	// 打开文件
	FILE* pf = fopen("text.txt", "r");
	if (pf == NULL)
	{
		perror("fopen text.txt");
		return 1;
	}

	FILE* pw = fopen("text_cpy.txt", "w");
	if (pw == NULL)
	{
		perror("fopen text_cpy.txt");
		fclose(pf);
		pf = NULL;
		return 1;
	}

	// 读取并且写入
	int ch = 0;
	while ((ch = fgetc(pf)) != EOF)
	{
		fputc(ch, pw);
	}

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

使用 fputs 和 fgets 函数 

//使用 fputs 和 fgets 函数

int main()
{
	// 打开文件
	FILE* pf = fopen("fputs.txt", "w");
	if (pf == NULL)
	{
		perror("fopen fputs.txt");
		return 1;
	}

	// 使用 fputs函数写文件
	// 函数原型
	// int fputs(const char* str, FILE * stream);
	// const char* str 传入读取的字符串的首地址
	// FILE* stream 将读取的内容写入文件中

	char ch[] = "ouyang is cool\n";
	fputs(ch, pf);
	fputs("hello ouyang", pf);

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


int main()
{
	// 打开文件
	FILE* pf = fopen("fputs.txt", "r");
	if (pf == NULL)
	{
		perror("fopen fputs.txt");
		return 1;
	}

	// 使用 fgets函数读取文件
	// 函数原型
	// char* fgets(char* str, int num, FILE * stream);
	// char* str 函数将读取到的数据返回char*类型指针的首地址
	// int num  读取的长度
	// FILE* stream 读取文件的地址
	// 如果读取失败会返回NULL

	char ch[20] = { 0 };

	// 单个读取
	/*fgets(ch, 20, pf);
	printf("%s", ch);*/

	// 连续读取
	while (fgets(ch, 20, pf) != NULL)
	{
		printf("%s", ch);
	}
	
	// 关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}

使用 fprintf函数和 fscanf 函数 

typedef struct stu
{
	char name[20];
	int age;
	char sex[5];
}S;

int main()
{
	// 打开文件并且写入
	FILE* pf = fopen("fprintf.txt", "w");
	if (pf == NULL)
	{
		perror("fopen fprintf.txt");
		return 1;
	}

	// 写入
	S s = { "欧阳",20,"男" };
	fprintf(pf, "%s %d %s", s.name, s.age, s.sex);


	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}
typedef struct stu
{
	char name[20];
	int age;
	char sex[5];
}S;
int main()
{
	// 打开文件并且写入
	FILE* pf = fopen("fprintf.txt", "r");
	if (pf == NULL)
	{
		perror("fopen fprintf.txt");
		return 1;
	}

	// 读取文件
	S s = {0};
	fscanf(pf, "%s %d %s", s.name, &(s.age), s.sex);

	// 打印在屏幕上观察
	printf("%s %d %s", s.name, s.age, s.sex);

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

有关于流的概念

  • stdin - 标准输入流,获取我们输入的信息。
  • stdout - 标准输出流,输出我们需要打印的信息
  • fgetc, fgets, fputc, fputs, fscanf, fprintf - 适用于所有流
  • fread, fwrite - 适用于文件流
// 使用标准流

int main()
{
	fputc('a', stdout);
	return 0;
}

 使用 fwrite 和 fread 函数

 

int main()
{
	// 以二进制的形式写文件
	FILE* pf = fopen("fwrite.txt", "wb");
	if (pf == NULL)
	{
		perror("fopen fwrite.txt");
		return 1;
	}

	// 写二进制文件

	// fwrite 函数
	// 函数原型:
	// size_t fwrite(const void* ptr, size_t size, size_t count, FILE * stream);
	// const void* ptr - 指向要写入文件的数据
	// size_t size - 指向数据类型的大小
	// siez_t count -指向数据的数量
	// FILE * stream - 写入的文件指针

	int arr[] = { 1,2,3,4,5 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	fwrite(arr, sizeof(arr[0]), sz, pf);

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

int main()
{
	// 打开文件
	FILE* pf = fopen("fwrite.txt", "rb");
	if (pf == NULL)
	{
		perror("fopen fwrite.txt");
		return 1;
	}

	// 读取文件
	// fread 函数
	// 函数原型:
	// size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );
	// const void* ptr - 指向要读取文件的数据
	// size_t size - 指向数据类型的大小
	// siez_t count -指向数据的数量
	// FILE * stream - 要读取的文件指针
	int arr[5] = { 0 };
	fread(arr, sizeof(arr[0]), 5, pf);
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		printf("%d ", arr[i]);
	}

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

文件的随机读写 - 适用于二进制文件

 fseek 函数

// 函数原型:
// int fseek ( FILE * stream, long int offset, int origin );

// FILE * stream - 指向FILE*文件对象的指针
// long int offset - 偏移的字节数
// int origin - 参考位置
// 如:
//SEEK_SET	文件开头
//SEEK_CUR	文件指针的当前位置
//SEEK_END	文件末尾*


int main()
{
	// 读写文件
	FILE* pf = fopen("fseek.txt", "wb");
	if (pf == NULL)
	{
		perror("fopen fseek.txt");
		return 1;
	}

	// 读写
	fputs("hello ouyang",pf);
	fseek(pf, 6, SEEK_SET);
	fputs("to ", pf);

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

int main()
{
	// 打开并且读文件
	FILE* pf = fopen("fseek.txt", "rb");
	if (pf == NULL)
	{
		perror("fopen fseek.txt");
		return 1;
	}

	// 读取文件
	char ch[200] = { 0 };
	while (fgets(ch, 50, pf) != NULL)
	{
		printf("%s\n", ch);
	}

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

ftell 函数 

// 函数原型:
// long int ftell ( FILE * stream );

int main()
{
	// 读写文件
	FILE* pf = fopen("fseek.txt", "rb");
	if (pf == NULL)
	{
		perror("fopen fseek.txt");
		return 1;
	}

	// ftell 函数的使用
	fseek(pf, 6, SEEK_SET);
	long size = ftell(pf);
	printf("Size of myfile.txt: %ld bytes.\n", size);

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

 rewind 函数

// 函数原型:
// void rewind ( FILE * stream );

int main()
{

	// 打开文件并且写入
	FILE* pf = fopen("myfile.txt", "w+");
	char buffer[27];
	int n = 0;
	for (n = 'A'; n <= 'Z'; n++)
		fputc(n, pf); //写入之后的光标在最后
	rewind(pf); // 回调光标
	fread(buffer, 1, 26, pf); // 将文件中的数据读取到字符数组中

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

	// 打印观察
	buffer[26] = '\0'; // 方便输出字符串,将最后一位设置为'\0'
	printf(buffer); // 打印
	return 0;
}

 文件读取结束的判定

 feof 函数
 注意:该函数不可以通过该函数的返回值来直接判断文件的结束

 作用是当文件结束时,判断是读取失败的原因,还是遇到文件结尾结束

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

int main()
{
	int c = 0; // 注意:int,⾮char,要求处理EOF
	FILE* fp = fopen("test.txt", "r");
	if (fp==NULL) 
	{
		perror("File opening failed");
		return 1;
	}


	//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);
	fp = NULL;
}

文件缓冲区

我们在程序中向文件中写入数据不会是有一条写一条,打个比方说:一个学生
问问题不是说问完一个过几分钟又问一个,则会导致老师无法为其他同学解答
问题,操作系统也是如此,操作系统不光是为了写入文件而服务的,所有这个学生
就会将问题攒着,直到一定的数量就可以去问老师,同理我们写入的文件也是如此
而存放这些数据的空间就叫做文件缓冲区

源代码地址:text_2024_3_26 · 6988b68 · 阳区欠/C语言学习路程 - Gitee.com

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

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

相关文章

【并发】第二篇 ThreadLocal详解

导航 一. ThreadLocal 简介二. ThreadLocal 源码解析1. get2. set3 .remove4. initialValue三. ThreadLocalMap 源码分析1. 构造方法2. getEntry()3. set()4. resize()5. expungeStaleEntries()6. cleanSomeSlots()7. nextIndex()8. remove()9. 总结ThreadLocalMap四. 内存泄漏…

校园局域网钓鱼实例

Hello &#xff01; 我是"我是小恒不会java" 本文仅作为针对普通同学眼中的网络安全&#xff0c;设计的钓鱼案例也是怎么简陋怎么来 注&#xff1a;本文不会外传代码&#xff0c;后端已停止使用&#xff0c;仅作为学习使用 基本原理 内网主机扫描DNS劫持前端模拟后端…

算法题剪格子使我重视起了编程命名习惯

剪格子是一道dfs入门题。 我先写了个dfs寻找路径的模板&#xff0c;没有按题上要求输出。当我确定我的思路没错时&#xff0c;一直运行不出正确结果。然后我挨个和以前写的代码对比&#xff0c;查了两个小时才发现&#xff0c;是命名风格的问题。 我今天写的代码如下&#xff…

03---java面试八股文——mybatis-------8题

21、MyBatis实现一对一查询 MyBatis 有两种不同的方式加载关联&#xff1a; 嵌套 Select 查询&#xff1a;通过执行另外一个 SQL 映射语句来加载期望的复杂类型。嵌套结果映射&#xff1a;使用嵌套的结果映射来处理连接结果的重复子集。查看mybatis的关联 MyBatis是一种流行的J…

基于springboot的船舶维保管理系统

文章目录 项目介绍主要功能截图&#xff1a;部分代码展示设计总结项目获取方式 &#x1f345; 作者主页&#xff1a;超级无敌暴龙战士塔塔开 &#x1f345; 简介&#xff1a;Java领域优质创作者&#x1f3c6;、 简历模板、学习资料、面试题库【关注我&#xff0c;都给你】 &…

Java研学-SpringBoot(四)

六 SpringBoot 项目搭建 1 创建项目 spring2.X版本在2023年11月24日停止维护&#xff0c;而Spring3.X版本不支持JDK8&#xff0c;JDK11&#xff0c;最低支持JDK17&#xff0c;目前阿里云还是支持创建Spring2.X版本的项目 2 修改所需依赖版本 – pom <?xml version&quo…

Platypus 一种集中式的央行数字货币方案

集中式的CBDC&#xff0c;混合使用账户模型和UTXO模型。 角色分类 中央银行&#xff1a;发行货币&#xff0c;交易验证&#xff0c;公开交易日志&#xff0c;防止双花。 不是完全受信任的&#xff0c;假定为会遵守监管要求&#xff0c;但可能会破坏交易隐私&#xff0c;即获…

C语言——字符串函数

一.前言 我们在日常写代码的过程中&#xff0c;经常会对字符串进行处理的过程。而在C语言中的<string.h>中&#xff0c;包含了众多字符串函数&#xff0c;我们可以借助这些字符串函数来对其进行各种操作。 二.strlen函数 strlen函数的作用是求出所传字符串的长度。该函…

spring-boot之shiro安全框架配置使用

shiro架构&#xff08;外部&#xff09; shiro架构(内部) 具体API操作 获取当前的用户对象 Subject currentUser SecurityUtils.getSubject();通过当前用户拿到session Session session currentUser.getSession(); session.setAttribute("someKey", "aValu…

Android 自定义坐标曲线图(二)

Android 自定义坐标曲线图_android 自定义曲线图-CSDN博客 继上一篇文章&#xff0c;点击折线图上的点&#xff0c;显示提示信息进行修改&#xff0c;之前通过回调&#xff0c;调用外部方法&#xff0c;使用popupwindow或dialog来显示&#xff0c;但是这种方法对于弹框显示的位…

SpringCloud实用篇(二)——搭建eureka服务

搭建eureka服务 搭建EurekaServer 注册eureka自己本身 1.创建项目&#xff0c;引入spring-cloud-starter-neflix-eureka-server的依赖 <!--eureka服务端--> <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cl…

Windows 远程访问 Ubuntu Desktop - 虚拟网络控制台 (Virtual Network Console,VNC)

Windows 远程访问 Ubuntu Desktop - 虚拟网络控制台 [Virtual Network Console&#xff0c;VNC] References 1. Desktop Sharing 2. Desktop Sharing Preferences 勾选 允许其他人查看您的桌面 勾选 要求远程用户输入此密码 取消勾选 必须为对本机器的每次访问进行确定 3. 虚拟…

Qt 富文本处理 (字体颜色大小加粗等)

Qt中支持HTML的控件有textEdit 、label 、textBrowser 。 接口&#xff1a;setHtml("Qt"); toHtml(). 文本样式设置 : 可分字设置 &#xff0c;主要使用QTextCharFormat类进行文本样式设置。 示例&#xff1a; QTextCharFormat fmt; //粗体 fmt.setFontWeight…

Linux中常用命令(文件、目录和文件压缩)及功能示例

一、Linux关于文件与目录的常用命令及其功能示例 命令: ls 全名: List (列表) 常用选项: -l: 详细列表格式&#xff0c;显示详细信息。-a: 显示所有文件&#xff0c;包括隐藏文件。 功能: 列出目录内容。 示例: ls -la /home 此命令以详细格式列出/home目录中的所有文件&#x…

openLooKeng开发环境搭建

文章目录 搭建OpenLooKeng开发环境要求 以下是搭建OpenLooKeng开发环境的基本步骤&#xff1a;1、从OpenLooKeng的GitHub仓库克隆代码&#xff1a;2、 构建OpenLooKeng生成IntelliJ IDEA项目文件 airbase构建项目过程中出现的问题checkstyle错误版本冲突问题hetu-heuristic-ind…

java将文件转成流文件返回给前端

环境&#xff1a;jdk1.8&#xff0c;springboot2.5.3,项目端口号&#xff1a;9100 1.待转换的文件 一、路径 二、文件内容 2.controller中代码 package com.example.pdf.controller;import com.example.pdf.service.GetFileStreamService; import org.springframework.web.b…

linux离线安装jdk

一、下载jdk 地址: Java Downloads | Oracle 中国 具体下载什么版本要根据安装的linux系统架构来决定&#xff0c;是ARM64还是X64&#xff0c;linux命令行输入如下命令 uname -m 可以看到linux系统是x64 架构(x86是32位&#xff0c;x86_64是64位&#xff0c;由于x86已经淘汰&…

正弦实时数据库(SinRTDB)的使用(8)-过滤查询

前文已经将正弦实时数据库的使用进行了介绍&#xff0c;需要了解的可以先看下面的博客&#xff1a; 正弦实时数据库(SinRTDB)的安装 正弦实时数据库(SinRTDB)的使用(1)-使用数据发生器写入数据 正弦实时数据库(SinRTDB)的使用(2)-接入OPC DA的数据 正弦实时数据库(SinRTDB)…

腾讯 tendis 替代 redis linux安装使用

下载地址 Tendis存储版 点击下载 linux 解压 tar -zxvf 安装包.tgz cd 解压安装包/scripts 启动 ./start.sh 停止 ./stop.sh 详细配置 修改 /scripts tendisplus.conf # tendisplus configuration for testing # 绑定本机IIP bind 192.168.31.112 port 51002 #设…

C++ :STL中deque的原理

deque的结构类似于哈希表&#xff0c;使用一个指针数组存储固定大小的数组首地址&#xff0c;当数据分布不均匀时将指针数组内的数据进行偏移&#xff0c;桶不够用的时候会像vector一样扩容然后将之前数组中存储的指针拷贝过来&#xff0c;从原理可以看出deque的性能是非常高的…