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语言学习之路————文件操作

文件一般指的就是在电脑磁盘上的文件,而在我们学习程序设计的时候文件一般分别为程序文件和数据文件

?

程序文件:它包含我们代码的源文件(.c)、目标文件(.obj)、可执行文件(.exe)

数据文件:该文件内容不一定是程序,而是在程序执行的过程中,要写和读数据的文件,而数据文件的类型又分为文本文件(我们直观的可以看明白的)、二进制文件(机器可以识别的)

在这里补充一个知识:文件缓冲区的概念,在标准里采用“缓冲文件系统”处理数据文件,这个系统是指在使用文件,或操作文件时会在内存中开辟一块空间叫文件缓冲区,无论是向文件输出数据,还是从文件输入数据,都需要先将先将数据先放到这块区域里,然后等缓冲区充满之后,再将缓冲区的数据进行传输(到磁盘文件或者到程序数据区),而缓冲区的大小是编译系统决定的。

1.关于文件的操作我们先了解怎们去打开一个文件然后关闭一个文件

这里涉及到两个函数? ?FILE* fopen(const char* file_name,const char* mode)? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 首先而后个函数的返回值为一个FILE结构体型的指针(这里的FILE是大写,它是包含一些文件信息属性的结构体),第一个参数为要打开文件的文件名,第二个参数是打开文件访问模式,下面是一些访问模式,而如果打开失败会返回NULL,成功会返回一个那个文件流的地址

?有时候会出现“rt”或者“wt”等样式其中“t”就是“text”操作的都是文本文件

而关闭文件的操作上是 int fclose(FILE* stream),参数为文件流,类似于指向文件的指针,而在关闭文件之后还需将这个指针置空。

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<errno.h>
#include<string.h>
int main()
{
	FILE* str = fopen("text.t", "w");//这是相对路径
    //FILE* str = fopen("../text.t", "w");表示上一级路径  “../../text.t”表示上上级路径  
    //“./text.t”表示当前路劲
    //FILE* str = fopen("D:\source about c\repos\10.21文件操作", "w");这是绝对路径
	if (str == NULL)
	{
		printf("%s", strerror(errno));
        //perror(“Error: ”);也是打印不成功的信息.
	}
	fclose(str);
	str = NULL;
	return 0;
}

这个text.t 文件就是我们上面打开的文件,它的位置和你项目存储的在同一位置?

2.我们需要了解打开文件之后对文件可以有哪些操作

文件的一个字符输入、输出函数? ? ?int fgetc(FILE* stream)? (从流中读)? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?int fputc(int char,FILE* stream)?(在文件中写)

fgetc:从目标流中获取一个字符,返回值为

fputc:第一个参数为要写入的字符,写入的目标流

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<errno.h>
#include<string.h>
int main()
{
	/*FILE* str = fopen("text.txt", "r");*///error   不能打开读取没有的文件,也就是“r”模式没有新建文件的功能
	FILE* str = fopen("text.t", "w");
	if (str == NULL)
	{
		/*printf("%s", strerror(errno));*/
		perror("");
	}
	//输出到文件里
	fputc('l', str);
	fputc('o', str);
	fputc('v', str);
	fputc('e', str);
	
	fputc('y', stdout);
	fputc('o', stdout);
	fputc('u', stdout);
	fclose(str);
	str = NULL;
	return 0;
}

?我们的输出的目标流可以是文件,也可以是标准输出设备(控制台屏幕stdout)

当然我们输入的目标流也可以是标准输入设备(键盘stdin)

3.读取一行文件数据的函数

char* fgets(char* string,int n,FILE*stream):第一个参数为从流中的读取的字符串要存储的地址,第二个参数为最多能读取的字符的个数,第三个是要读的目标流

(gtes、puts会将数据输入、输出到标准输出设备上? gets会在后面加一个“\n”,)

int fputs(const char* str,FILE* stream,):第一个参数为要输出的字符串的首地址,第二个参数为要输入的目标流

4.格式化文件输入输出

int fscan(FILE*stream,const char*format,[argument]...):第一个参数为输入目标流,第二个参数为文件数据要输出的格式,第三个数据是要把数据放到哪里(地址)(从文件读)

int fprint(FILE* stream,const char*format,[argument]...)第一个参数为要输出数据的流,第二个参数为要输出的形式,第三个参输提供数据的变量(给文件写)

#include<stdio.h>
int main()
{
	int a;
	int b;
	FILE* str = fopen("text.t", "r");
	if (str == NULL)
    {
			/*printf("%s", strerror(errno));*/
		perror("");
	}
	fscanf(str, "%d %d", &a, &b);
	printf("%d %d", a, b);
	fclose(str);
	str = NULL;
	return 0;
}

?上面文件里的1 2是我事先在文件里输好的,然后通过fscanf()读出来放到a和b中,在通过printf打印到屏幕上

?按照这个思路,那我们可以通过fprint()函数将一些参数格式化的输入到文件流里,当然也可以是标准输出流(stdout)

(scanf、printf只能使数据在标准输入输出设备上操作)

总结一下上面的三组函数(输入、输出)可以操作在任何流上,标准、文件等

下面一组函数将数据以格式化输入到字符串里,或者以格式化的形式从字符串中输出

int sprintf(char *str, char * format [, argument, ...]);(输入到字符串里)

int sscanf(const char *str, const char *format, ...)?:(从字符串里以格式化提取数据)

#include<stdio.h>
int main()
{
	int a = 12;
	char str[] = "anny";
	double b = 3.14;
	char buf[1024] = { 0 };
	sprintf(buf, "%d %s %lf", a, str, b);
	printf("%s", buf);
	return 0;
}

?这里是所有的数据以格式化的形式放到字符串中

#include<stdio.h>
int main()
{
	int a = 12;
	char str[] = "anny";
	double b = 3.14;
	//char buf[1024] = { 0 };
	//sprintf(buf, "%d %s %lf", a, str, b);
	//printf("%s", buf);
	char buf[1024] = { "45 jack 0.707" };
	sscanf(buf, "%d %s %lf", &a, str, &b);
	printf("%d %s %lf", a, str, b);
	return 0;
}

?这里是将数据包以格式化从字符串中提取数据,然后放到对应的类型变量中

4.只针对文件操作的输入输出(二进制输入输出)

??size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream)?

第一个参数为:程序中提供数据的变量地址,或着指向那个地址的指针

第二个参数:这块数据的大小

第三个参数:要写入多少个这样的数据

第四个参数:写入的流的地址

#include<string.h>
int main()
{
	char s[] = "hello world 20 ";
	int a=20;
	FILE*str = fopen("text.txt", "wb");
	if (str == NULL)
	{
		perror("");
		return 0;
	}
	fwrite(s, strlen(s), 1, str);
	fclose(str);
	str = NULL;
	FILE*str1 = fopen("text.txt", "ab");
	if (str1 == NULL)
	{
		perror("");
		return 0;
	}
	fwrite(&a, sizeof(int), 1, str1);
	fclose(str1);
	str1= NULL;
	return 0;
}

将20以二进制输入到文件里确实变成了我们看不懂的二进制语言,字符串常量没有改变 (这里的记事本是以文本方式打开文件,而文本文件是以字符编码的,所以我们熟悉的二十的二进制码转为十进制对应的字符是方框,总之显示方式与采用什么工具打开文件有关)

?size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream)?

第一个参数为:程序中接受数据的变量的地址或者说是指向那块地址的指针

第二个参数:这块数据的大小

第三个参数:要读取多少个这样的数据

第四个参数:读数据的流的地址

返回值返回当前读取数据的个数,返回成功读取的对象个数,

5.文件的随机读取

int fseek(FILE* stream,long int offset,int origin);

第一个参数:读取的流的地址

第二个参数:相对于第三个参数的偏移量

第三个参数:为开始偏移的的位置(1.文件开头SEEK_SET? ?2.当前位置SEEK_CUR? ? 3.文件末尾SEEK_END

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
int main()
{
	//fseek函数的使用
	//int fseek(FILE* stream,long int offset,int origin);
	char buf[] = "abcdef";
	char ch = 0;
	//打开一个文件
	FILE* pfwrite = fopen("text.t", "wb+");
	//检测打开是否成功
	if (pfwrite == NULL)
	{
		perror("Error:");
	}
	fwrite(buf, strlen(buf), 1, pfwrite);
	fseek(pfwrite, 3, SEEK_SET);
	printf("%c\n",fgetc(pfwrite));//d 这里的首字符地址指向的是a,偏移量为0,偏移量是3的指针指向的是d
	fseek(pfwrite, 0, SEEK_CUR);
	printf("%c\n", fgetc(pfwrite));//e
	fseek(pfwrite,-1, SEEK_END);
	printf("%c\n", fgetc(pfwrite));//f
	//关闭文件
	fclose(pfwrite);
	pfwrite = NULL;
	return 0;
}

在这里发现里一个关于fseek的第三个参数两种现象,就是当用完seek_set变换过偏移量之后,再用seek_cur会直接读取上次偏移量的下一个偏移量所对应的字符

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
int main()
{
	char buf[] = "abcdef";
	char ch = 0;
	//打开一个文件
	FILE* pfwrite = fopen("text.t", "wb+");
	//检测打开是否成功
	if (pfwrite == NULL)
	{
		perror("Error:");
	}
	fwrite(buf, strlen(buf), 1, pfwrite);
	fseek(pfwrite, 0, SEEK_SET);
	printf("%c\n", fgetc(pfwrite));//a 
	fseek(pfwrite, 0, SEEK_CUR);
	printf("%c\n", fgetc(pfwrite));//b
	//关闭文件
	fclose(pfwrite);
	pfwrite = NULL;
	return 0;
}

而如果没有变换过偏移量直接使用seek_cur会读不到文件里的字符(用读加写模式)

int main()
{
	char buf[] = "abcdef";
	//打开一个文件
	FILE* pfwrite = fopen("text.t", "r");
	//检测打开是否成功
	if (pfwrite == NULL)
	{
		perror("Error:");
	}
	fwrite(buf, strlen(buf), 1, pfwrite);
	fseek(pfwrite, 0, SEEK_CUR);
	printf("%c\n", fgetc(pfwrite));//a
	/*fseek(pfwrite, 1, SEEK_CUR);
	printf("%c\n", fgetc(pfwrite));*/
	//关闭文件
	fclose(pfwrite);
	pfwrite = NULL;
	return 0;
}

?如果用只读模式就可以读出来

总结一下,就是在每次定位读之后再都当前字符,将会跳到下一个字符,用只读(“r”“rb”)都可以读出为变化过的seek_cur的偏移位置的,如果用读加写模式就不能读出当前偏移量的字符

?7.让文件指针返回文件初始位置

void rewind(FILE* stream)

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

long int ftell(FILE* stream)

int main()
{
	char buf[] = "abcdef";
	//打开一个文件
	FILE* pfwrite = fopen("text.t", "r");
	//检测打开是否成功
	if (pfwrite == NULL)
	{
		perror("Error:");
	}
	fwrite(buf, strlen(buf), 1, pfwrite);
	fseek(pfwrite, -2, SEEK_END);
	long pos = ftell(pfwrite);
	printf("%c\n", fgetc(pfwrite));//e
	printf("%ld", pos);//4   a的偏移量为0
	/*fseek(pfwrite, 1, SEEK_CUR);
	printf("%c\n", fgetc(pfwrite));*/
	//关闭文件
	fclose(pfwrite);
	pfwrite = NULL;
	return 0;
}

8.文件结束判定

int feof(FILE *stream);

应用于文件结束时,判断是读取失败还是文件读取结束

int main()
{
	FILE* pf = fopen("text.tx", "w+");
	if (pf == NULL)
	{
		/*perror("");*/
		return 0;
	}
	int ch = fgetc(pf);
	printf("%d", ch);//-1   end of file 的值是-1,这也就是文件结束标志
	fclose(pf);
	pf = NULL;
	return 0;
}

fgetc得到end of file和fgets得到NULL都是文件结束的标志

9.ferror函数? int ferror(FILE *stream);

如果ferror返回值为0(假),表示未出错。如果返回一个非零值,表示出错,对同一个文件 每一次调用输入输出函数,均产生一个新的ferror函 数值,因此,应当在调用一个输入输出函数后立即检 查ferror函数的值,测试流上的错误

//判断是什么原因结束的
int main()
{
	int c;
	FILE* pf = fopen("text.t", "w+");
	if (pf == NULL)
	{
		perror("");
		return 0;
	}
	
	while ((c = fgetc(pf) != EOF))
	{
		putchar(c);
	}
	if (ferror(pf))
		puts("读的过程中出错\n");
	else if (feof(pf))
		puts("文件结束\n");
	return 0;
}

?

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-10-23 12:18:07  更:2021-10-23 12:18:52 
 
开发: 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年11日历 -2024/11/24 3:30:19-

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