c语言中文件操作详解

目录

一、c语言中的文件

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

[2. 文件概念](#2. 文件概念)

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

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

[2.2.1 文本文件](#2.2.1 文本文件)

[2.2.2 二进制文件](#2.2.2 二进制文件)

[3. 流的概念](#3. 流的概念)

[3.1 流](#3.1 流)

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

二、c语言中文件的使用

[1. 文件指针的使用(fopen和fclose)](#1. 文件指针的使用(fopen和fclose))

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

[3. 读写函数介绍](#3. 读写函数介绍)

[3.1 fputc字符输出fputs字符串输出](#3.1 fputc字符输出fputs字符串输出)

[3.2 fgetc字符输入fgets字符串输入](#3.2 fgetc字符输入fgets字符串输入)

[3.3 fprintf对文本输出](#3.3 fprintf对文本输出)

[3.4 fscanf从文本输入](#3.4 fscanf从文本输入)

[3.5 fwrite写二进制到文本](#3.5 fwrite写二进制到文本)

[3.6 fread读取二进制文本](#3.6 fread读取二进制文本)

[4. 读取完成或失败的判断](#4. 读取完成或失败的判断)

[4.1 fgetc读取完的判断](#4.1 fgetc读取完的判断)

[4.2 fgets读取完的判断](#4.2 fgets读取完的判断)

三、文件随机读取

[1. fseek指向某个位置](#1. fseek指向某个位置)

[2. ftell判断光标与起始偏移量](#2. ftell判断光标与起始偏移量)

[3. rewind重置到起始](#3. rewind重置到起始)

四、文件缓存区


一、c语言中的文件

1. 为什么使用

文件是用来存储数据信息的,因为我们程序结束后,数据会全部消失,内存全部回收,无法寻找,这个时候就需要数据文件来存储信息(用于持久化保存)。

2. 文件概念

2.1 程序文件

程序文件就是我们执行代码的.c文件、windows环境的.obj文件和可执行.exe文件。

2.2 数据文件(最后提一下数据文件概念)

2.2.1 文本文件

文本文件就是通过将字符(一个字节)对应的ascll值保留到文件中,这个过程需要将字符(数字也会当成字符)转换为一个一个的ascll值,然后进行存储每个字符对应的ascll值的二进制。

2.2.2 二进制文件

二进制文件,会将一个数据的二进制存储起来,不做任何修改

两个文件的区别图示:

数据文件,就是存储 信息,这个数据文件的信息是可以通过程序文件进行读取和修改的,。可以通过程序文件与数据文件传输数据来保留和修改数据,最主要的就是可以保留程序运行时产生的数据。

3. 流的概念

3.1 流

我们程序需要输出输入外部设备的内容,而每个外部设备不一样,为了方便写代码,这里引用了流的概念。可以把流当成流淌字符的河,用于流淌数据传输过去。

3.2 标准流

一般编译器默认打开这几个标准流,stdin这个输入流,stdout这个输出流,还有一个错误流stderr。这几个流类型都是FILE*这个指针类型,统称文件指针

二、c语言中文件的使用

1. 文件指针的使用(fopen和fclose)

fopen是打开文件的函数,如果打开失败,那就会返回NULL这个空指针,而如果打开成功,那就可以进行读写等操作。格式为FILE* pf = fopen("文件名","读取方式"),文件是由路径+文件主干+后缀,fopen文件名可以直接写成文件主干+后缀,表示在当前文件中寻找这个需要修改或者读取的文件名。文件路径包0括范围路径、绝对路径还有相对路径。这里绝对路径就是将整个文件名都表示出来了,把这个文件的所在地方都表示

出来了,在程序中打开文件,我们需要将/这些转义字符转换/这个普通斜杠;而范围路径指的是当前文件中寻找这个文件;相对路径也是范围路径的一种,就是以当前路径作为参考物,取上一个路径或者上上个路径,这个时候就需要..来表示上个路径(首先用.来表示当前路径)。

cs 复制代码
FILE* pf = fopen("C:\\Users\\bearone\\Desktop\\test.c")//绝对路径
                    \User\bearone\Desktop\test.c
cs 复制代码
FILE* pf = fopen("./test.c","r");//当前路径
FILE* pf = fopen("./../test.c","r");//上个路径
FILE* pf = fopen("./../../test.c","r");上上个路径

fclose是用于关闭文件的函数,格式为fclose("FILE* ")。一般关闭后我们需要将这个文件指针置空(空指针)

cs 复制代码
#include<stdio.h>
int main()
{
	int a = 10000;
	FILE* pf = fopen("test.txt", "wb");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	else
	{
		printf("打开文件成功");
	}
	写文件
	fwrite(&a, 4, 1, pf);//以二进制输入到指针文本
	fclose(pf);
	pf = NULL;
}

2. 文件读写顺序

3. 读写函数介绍

写之前,我给大家展示一个图,方便好理解

3.1 fputc字符输出fputs字符串输出

fputc用来输出字符到文本 的函数,而fputs输出字符串到文本 中去。格式为(int)fputc(int(字符自动转换为ascll值),文件指针),而(int成功返回非零值,失败返回NULL)fputs(const 类型*,文件指针)

fputc实例

cs 复制代码
#include<stdio.h>
int main()
{
	FILE* pf = fopen("test.txt", "w");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	for (int i = 'a'; i <= 'z'; i++)
	{
		fputc(i, pf);
	}
	fclose(pf);
	pf = NULL;
	return 0;
}

fputs实例

cs 复制代码
#include<stdio.h>
int main()
{
	char str[] = "abcdefghijklmnopqrstuvwxyz";
	FILE* pf = fopen("test.txt", "w");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	fputs(str, pf);
	fclose(pf);
	pf = NULL;
	return 0;
}

均输出到文本为:

3.2 fgetc字符输入fgets字符串输入

fgetc是从文本输入字符到程序 中,每一次读取都会使得光标往后移,而fgets是从文本输入字符串到程序中 。fgetc格式为(int)fgetc(文件指针),fgets格式char* fgets(char* str,int(读取最多字符个数),文件指针),这里fgets是指将文本中的信息输入到char* str这个指针中,这里读取的最大字符个数,如果读取最大个数小于实际中的个数那就会读取不完全,如最大读取为10,那么就会读取9个字符,如果读取最大个数大于实际中的个数,那就会读到最后一个字符就停止,最大10个,实际5个,那就会读到第6取\0(这个\0是必须加的,fgets会自动补充)。fgets只会读取到一行中的字符串 ,如果第二行还有字符,并且还没到达最大字符个数,它也不会继续读取(注意fgetc会读取第二行)。

fgetc实例 :

cs 复制代码
#include<stdio.h>
int main()
{
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	char ch = 0;
	while ((ch = fgetc(pf)) != EOF)
	{
		printf("%c", ch);
	}
	fclose(pf);
	pf = NULL;
	return 0;
}

fgets实例:

cs 复制代码
#include<stdio.h>
#include<stdlib.h>
int main()
{
	FILE* pf = fopen("test.txt", "r");//打开文件
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	char* str = malloc(27);//开辟
	if (str == NULL)
	{
		perror("malloc");
		return 1;
	}
	fgets(str, 27, pf);
	printf("%s", str);
	fclose(pf);
    free(str);
    str = NULL;
	pf = NULL;
	return 0;
}

3.3 fprintf对文本输出(扩展sprintf)

fprintf这个用于格式化输出到流 中,将程序文件打印到对应流中。格式为(int)fprintf(FILE*stream,这里printf一样)。

cs 复制代码
#include<stdio.h>
struct Stu
{
	char name[20];
	char id[20];
};

int main()
{
	struct Stu s1 = { "zhansan","2403020650" };
	FILE* pf = fopen("test.txt", "w");
	if (pf == NULL)
	{
		perror("fopen");
		return  1;
	}
	fprintf(pf, "name is %s\nid is %s", s1.name, s1.id);//打印到文件指针中
	fprintf(stdout, "name is %s\nid is %s", s1.name, s1.id);//打印到屏幕中(标准流)
	fclose(pf);
	pf = NULL;
	return 0;
}

sprintf直接输出字符串到对应的指针中。 代码实例

cs 复制代码
#include<stdio.h>
int main()
{
	char arr[30];
	int id = 24030206;
	sprintf(arr, "id = %d", id);
	printf(arr);
	return 0;
}

3.4 fscanf从文本输入(扩展sscanf)

fscanf只不过意义变了格式化输入,格式都和scanf差不多,fscanf是向通过流输入到程序文件中 。fscanf(FILE*stream,和scanf使用一样)。

cs 复制代码
#include<stdio.h>
struct Stu
{
	char name[20];
	char id[20];
}s1;
int main()
{
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	fscanf(pf, "%s %s", s1.name, s1.id);//文件输入
	fscanf(stdin, "%s %s", s1.name, s1.id);//键盘输入
	printf("%s\n%s\n", s1.name, s1.id);
	fclose(pf);
	pf = NULL;
	return 0;
}

sscanf是读取指针中数据到后面的变量中去。代码实例

cs 复制代码
#include<stdio.h>
int main()
{
	char arr[30];
	char id1[] = "2403020650";
	char id2[20];
	sprintf(arr, "id1=%s\n", id1);//右输出到左
	printf(arr);
	sscanf(arr, "%s", &id2);//左输入到右
	printf("%s\n", id2);
	return 0;
}

3.5 fwrite写二进制到文本

fwrite以二进制的形式写到文本 中,也就是二进制文本。格式为fwrite(const void* ,szie_t(一个元素所占字节大小),size_t (元素个数),FILE*(流))。将指针中二进制放入流中,返回值为放入元素的个数。

cs 复制代码
#include<stdio.h>
int main()
{
	int arr[] = { 0,1,2,3,4,5,6,7,8,9 };
	//打开文件
	FILE* pf = fopen("test.txt", "wb");//以二进制写
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//使用
	fwrite(arr, sizeof(int), 9, pf);
	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}

小端存储

3.6 fread读取二进制文本

fread就是读取二进制文件 ,将二进制文本读取到程序中来。格式和fwrite一模一样,fread(const void* ,size_t (一个元素占的字节大小),size_t (元素个数),FILE*(流))。返回的是读取元素个数(可以通过比较读取个数是否和自己输入个数一样来判断读取完毕)。

cs 复制代码
#include<stdio.h>
int main()
{
	int arr1[] = { 0,1,2,3,4,5,6,7,8,9 };
	//打开文件
	FILE* pf = fopen("test.txt", "wb");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//使用
	fwrite(arr1, sizeof(int), 9, pf);
	//关闭文件
	fclose(pf);
	pf = NULL;
	int arr2[10];
	 pf = fopen("test.txt", "rb");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	fread(arr2, sizeof(int), 9, pf);
	for (int i = 0; i < 9; i++)
	{
		printf("%d ", arr2[i]);
	}
	//关闭
	fclose(pf);
	pf = NULL;
	return 0;
}

这些函数区别。

4. 读取完成或失败的判断

4.1 fgetc读取完的判断

fgetc读取成功会返回对应的ascll值,失败或者读取到文件末尾则会返回EOF。

cs 复制代码
#include<stdio.h>
int main()
{
	//打开
	FILE* pf = fopen("test.txt", "w");//写
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//使用
	for (int i = 'a'; i <= 'z'; i++)
	{
		fputc(i, pf);
	}
	//关闭
	fclose(pf);
	pf = NULL;
	char ch = 0;
	//打开
	pf = fopen("test.txt", "r");//读
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//使用
	while ((ch = fgetc(pf)) != EOF)
	{
		printf("%c", ch);
	}
	printf("\n");
	if (feof(pf))
	{
		printf("读完\n");
	}
	else if (ferror(pf))
	{
		printf("错误\n");
	}
	//关闭
	fclose(pf);
	pf = NULL;
	return 0;
}

4.2 fgets读取完的判断

fgets读取成功就会返回该指针的起始地址,失败或读取到文件末尾则返回NULL空指针。

feof和ferror这俩个区别,feof对于读取失败错误信息,它会返回0,而对于正常读取文件结束,会返回非零。ferror就和它相反,失败就返回非零,成功读取结束返回0;

三、文件随机读取

1. fseek指向某个位置

fseek用于定位指针指向的某个位置,意思就是可以将光标移动到某一位,格式为fseek(FILE*(流),long int offset(相对于某个位置偏移量),int origin(SEEK_SET起始位置)(SEEK_OUR当前光标)(SEEK_END文件末尾))),通过对origin使用和偏移量的使用,将光标移动到想要的位置上。

cs 复制代码
#include<stdio.h>
int main()
{
	//打开
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//使用
	char ch = 0;
	ch = fgetc(pf);
	printf("%c\n", ch);
	fseek(pf, -3, SEEK_END);
	ch = fgetc(pf);
	printf("%c\n", ch);
	//关闭
	fclose(pf);
	pf = NULL;
	return 0;
}

2. ftell判断光标与起始偏移量

ftell用于计算此时光标与起始位置的偏移量。格式为(long int)ftell(FILE*流)。

cs 复制代码
#include<stdio.h>
int main()
{
	//打开
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//使用
	char ch = 0;
	ch = fgetc(pf);
	printf("%c\n", ch);
	fseek(pf, -3, SEEK_END);
	ch = fgetc(pf);
	printf("%c\n", ch);
	long int r = ftell(pf);
	printf("%d\n", r);
	//关闭
	fclose(pf);
	pf = NULL;
	return 0;
}

3. rewind重置到起始

rewind将光标重置到起始位置 。格式为rewind(FILE*流)。

cs 复制代码
#include<stdio.h>
int main()
{
	//打开
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//使用
	char ch = 0;
	ch = fgetc(pf);
	printf("%c\n", ch);
	fseek(pf, -3, SEEK_END);
	ch = fgetc(pf);
	printf("%c\n", ch);
	rewind(pf);
	long int r = ftell(pf);
	printf("%d\n", r);
	//关闭
	fclose(pf);
	pf = NULL;
	return 0;
}

四、文件缓存区

用于提高效率

相关推荐
T.Ree.15 分钟前
【数据结构】_树和二叉树
c语言·开发语言·数据结构
夜夜敲码26 分钟前
C语言教程(十五):C 语言函数指针与回调函数详解
c语言·开发语言
Cao12345678932127 分钟前
判断是否为闰年(C语言)
c语言·开发语言
是发财不是旺财38 分钟前
跟着deepseek学golang--认识golang
开发语言·后端·golang
Bruce_Liuxiaowei1 小时前
基于Python+Flask的MCP SDK响应式文档展示系统设计与实现
开发语言·python·flask·mcp
chuxinweihui1 小时前
数据结构——栈与队列
c语言·开发语言·数据结构·学习·算法·链表
我不是程序猿儿1 小时前
[C#]反射的实战应用,实际数据模拟
开发语言·c#
wt_cs2 小时前
身份证实名认证接口数字时代的信任基石-node.js实名认证集成
开发语言·node.js·php
爱编程的鱼2 小时前
C# 结构(Struct)
开发语言·人工智能·算法·c#
只可远观2 小时前
Flutter Dart 循环语句 for while do..while break、continue
开发语言·javascript·ecmascript