IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C语言文件操作 -> 正文阅读

[C++知识库]C语言文件操作

文件指针和文件信息区

每个被使用的文件都在内存中开辟了一个相应的文件信息区,用来存放文件的相关信息(如文件的名字,文件状态及文件当前的位置等)。这些信息是保存在一个结构体变量中的。该结构体类型是有系统声明的,取名FILE.

FILE结构体大致是这样,每个编译器都不太相同,但大同小异

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

上面说的都不重要。我们只需要知道有这么一个文件信息区就可以了。

我们使用的时候不需要关注这些细节。我们只需要知道我们可以用文件指针来指向这块文件信息区就可以了。

FILE* pf//文件指针

在这里插入图片描述

二进制文件和文本文件

二进制文件就是指文件里面的数据都是二进制。
文本文件就是指文件里面的数据都是由ASCII翻译而来。

举个例子:
在文件里面存放数字10000.
二进制文件存储的就是10000的十六进制,占用的内存是4个字节(一个整型)
文本文件就是把1变成字符1,0变成字符0,存放进文件里面。占用的内存是5个字节。(5个字符)

如何用vs查看二进制文件

先写一个二进制文件。

int main()
{
	FILE* pf = fopen("C:\\Users\\86135\\Desktop\\test.txt", "wb");
	if (pf == NULL)
	{
		perror("fopen:");
		return -1;
	}
	int i = 10000;
	fwrite(&i, sizeof(int), 1, pf);
	fclose(pf);
	pf = NULL;
	return 0;
}

我们是看不懂的。
在这里插入图片描述
添加现有项,然后用二进制编辑器查看。
在这里插入图片描述
我们就可以看到这个信息。这是10000的十六进制形式。
在这里插入图片描述

文件缓冲区

从内存向磁盘输出数据会先送到内存中的缓冲区,装满缓冲区后才一起送到磁盘上。
在这里插入图片描述
下面用一段代码来说明:

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

刷新缓冲区会让缓冲区的内容写入磁盘里。

文件的打开和关闭

文件打开用fopen函数。
fopen函数会返回一个你想要打开的文件的指针,自己创建一个变量去接受就好了。

FILE* pf = fopen("文件名","打开方式");

文件关闭用fclose函数,传入对应文件的文件指针就可以了。

fclose(pf);

下面三个可以背一下,其他要用的时候查就好了。
很简单,不写例子了。

r:以只读的方式打开文本文件,文件必须存在;

w:以只写的方式打开文本文件,文件若存在则清空文件内容从文件头部开始写,若不存在则根据文件名创建新文件并只写打开;

a:以只写的方式打开文本文件,文件若存在则从文件尾部以追加的方式开始写,文件原来存在的内容不会清除(除了文件尾标志EOF),若不存在则根据文件名创建新文件并只写打开;

文件的顺序读写

大概有这么几个函数。

函数名 适用于
fgetc 所有输入流
fputc 所有输出流
fgets 所有输入流
fputs 所有输出流
fscanf 所有输入流
fprintf 所有输出流
fread 文件
fwrite 文件

在上面的几个函数中都出现了流(stream)这个概念,解释一下。
流是类的对象。
在这里插入图片描述

fgetc

fgetc是从任意输入流读取字符。

注:fgetc的返回值是int。
在这里插入图片描述

我们先测试从文件里面读取字符。

在桌面写了一个txt文件。
在这里插入图片描述

注:在写文件路径的时候,如果只写一个斜杠的话有可能出现转义字符。比如\t等。再写一个斜杠防止转义就可以了。

在这里插入图片描述
我们再测试从屏幕上读入字符。
代码如下:
在这里插入图片描述
stdin是标准输入流。其实就是从屏幕上读取字符。
在这里插入图片描述

fputc

fputc和fgetc的用法是类似的。

向文件内写入字符
在这里插入图片描述
在这里插入图片描述
向标准输出流输出字符
在这里插入图片描述

fgets

在这里插入图片描述

fgets的用处是从输入流里面得到字符串。
但是它的使用方法有些奇怪。

在这里插入图片描述
如果你想得到5个字符,他只会返回4个字符给你,最后一个字符帮你变成斜杠0.
在这里插入图片描述

fputs

fputs的用处是把字符串写到输出流。
在这里插入图片描述

结果:
在这里插入图片描述

fscanf

fscanf的用处是格式化读取数据

格式化读取数据的意思就是任意数据类型你都可以读取。和scanf一样。只不过fscanf可以读取文件里面的数据。

对比一下fscanf和scanf两个函数,发现没什么区别,就是fscanf要多传一个文件指针而已。
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

struct S
{
	char ch;
	int i;
	char name[20];
};

	struct S s = { 0 };
	fscanf(pf, "%c %d %s", &(s.ch), &(s.i), s.name);
	printf("%c %d %s", s.ch, s.i, s.name);
	

在这里插入图片描述

fprintf

fprintf和fscanf的使用方法差不多。

	struct S s = { 'a',1,"zhangsan" };
	fprintf(pf,"%c %d %s",s.ch,s.i,s.name);

这样就可以往文件里面写你想要的东西了。

fwrite

fwrite是以二进制形式把内容写入文件里面。
在这里插入图片描述

struct S
{
	char ch;
	int i;
	char str[20];
};
int main()
{
	FILE* pf = fopen("C:\\Users\\86135\\Desktop\\test.txt", "wb");
	struct S s = { 'a',1,"zhangsan" };
	fwrite(&s, sizeof(struct S), 1, pf);
	return 0;
}

结果:
在这里插入图片描述

fread

fread是以二进制形式读取文件内容
在这里插入图片描述

struct S
{
	char ch;
	int i;
	char str[20];
};
int main()
{
	FILE* pf = fopen("C:\\Users\\86135\\Desktop\\test.txt", "rb");
	struct S s = { 0 };
	fread(&s, sizeof(struct S), 1, pf);
	printf("%c %d %s", s.ch, s.i, s.str);
	return 0;
}

结果:
在这里插入图片描述

sscanf和sprintf

有这么一道题目,对比一下下面三个函数。

scanf/fscanf/sscanf

printf/fprintf/sprintf
前面两个函数就不说了。sscanf和sprintf说一下。这两个函数很有意思

sprintf函数可以将任意类型的数据转换成字符串形式。
在这里插入图片描述

int main()
{
	struct S s = { 'a',1,"zhangsan" };
	char str[20] = { 0 };//用str来接收
	sprintf(str, "%c %d %s", s.ch, s.i, s.str);
	printf(str);//把str打印出来看一下
	return 0;
}

这个时候已经是字符串了。
在这里插入图片描述

sscanf的用法也类似。
在这里插入图片描述

	struct S s = { 'a',1,"zhangsan" };
	char str[20] = { 0 };
	sprintf(str, "%c %d %s", s.ch, s.i, s.str);
	
	//现在str里面已经存放了信息了。
	struct S s2 = { 0 };
	sscanf(str, "%c %d %s",&(s2.ch),&(s2.i),(s2.str));//两个参数的位置不要写反
	printf("%c %d %s", s2.ch, s2.i, s2.str);

文件的随机读写

文件的随机读写的意思就是可以调整文件指针的位置,进行任意位置的访问。

fseek

在这里插入图片描述
offset是偏移量的意思,origin是现在的位置。库里面定义了几个宏,如下:
在这里插入图片描述
原先文件里面放着abcdef。现在用fseek让pf指针往后移动一个位置。原先fgetc得到的应该是a,现在是b了。

int main()
{
	//文件里面存放的是abcdef
	FILE* pf = fopen("C:\\Users\\86135\\Desktop\\test.txt", "rb");
	fseek(pf, 1, SEEK_SET);
	int ch = fgetc(pf);
	printf("%c\n", ch);
	return 0;
}

ftell

在这里插入图片描述
ftell可以告诉你当前指针的offsetof是多少。

	FILE* pf = fopen("C:\\Users\\86135\\Desktop\\test.txt", "rb");
	fseek(pf, 3, SEEK_SET);
	long offsetof = ftell(pf);
	printf("%d\n", offsetof);

输出的是3.

rewind

rewind可以让文件指针重新回到文件开头。

	FILE* pf = fopen("C:\\Users\\86135\\Desktop\\test.txt", "rb");
	fseek(pf, 3, SEEK_SET);
	long offsetof = ftell(pf);
	printf("%d\n", offsetof);
	rewind(pf);
	offsetof = ftell(pf);
	printf("%d", offsetof);

在这里插入图片描述

文件结束判定

ferror和feof

文件打开失败有几种可能,有可能是出现了错误,也有可能是遇到了文件结束符号eof。当文件打开失败的时候,我们要怎么判断是哪一个错误呢?

这时候我们就要使用ferror和feof了。如果ferror返回0,就是文件没有出错,即代表遇到了文件结束符号eof了。如果feof返回0,就是文件没有遇到eof,即代表文件出现了某些错误。

  1. 文本文件读取是否结束,判断返回值是否为EOF (fgetc),或者NULL(fgets)
    例如:
    fgetc判断是否为EOF.
    fgets判断返回值是否为NULL.
  2. 二进制文件的读取结束判断,判断返回值是否小于实际要读的个数。
    例如:
    fread判断返回值是否小于实际要读的个数。

下面这段代码能很好的说明问题。

int main()
{
    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);
}
  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-10-09 16:05:38  更:2021-10-09 16:07:21 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/19 21:34:53-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码