【C语言】0基础教程——文件操作
【C语言】0基础教程——文件操作
目录
ὁ为什么要使用文件
ὁ什么是文件
ὦἫ️文件
1.程序文件
2.数据文件
我们写代码的时候与文件是什么关系呢?
ὦἫ️文件名
ὦἫ️文件指针
文件信息区那这块内存在什么位置呢?
由什么来维护呢?
ὁ相关函数
ὦἫ️文件的打开和关闭(fopen,fclose)
文件有那些打开方式呢?
例一:只写
例二:只读
ὦἫ️文件的顺序读写
1.fputc
例一
2. fgetc
例二
.fguts
例三
4.fgets
例四
5.fprintf
例五
6.fscanf
例6
7.fwrite
例7
8.fread
例子8
9.fseek
例9
10.rewind
例10
11.feof
例11
ὁ文本文件和二进制文件
数据在文本文件中和在二进制文件中分别是怎么存储的?
ὁ面试题
ὁ为什么要使用文件
在上一篇文章里展示了如何构造一个通讯录,可是一旦程序退出后,空间便还给操作系统,不存在了,但是当我我们需要保留下这些文件时又无可奈何,所以这章通过学习文件操作,便可以实现保存信息功能啦。
ὁ什么是文件
ὦἫ️文件
磁盘上的文件即是文件,但我们从文件功能的角度看又往往分为两类
包括源程序文件(后缀为.c),目标文件(windows环境后缀为.obj),可执行程序(windows环境后缀为.exe)。
文件的内容不一定是程序,而是程序运行时读写的数据,比如程序运行需要从中读取数据的文件,或者输出内容的文件。
看下图
可能有人又不明白啦,为什么写是输出到文件,读是输入到内存里呢?
首先,可以先问问自己,真的知道什么内存吗?(博主经常听到有人说自己手机内存256G...一提运行内存就说8G)
比如,你买了个手机,是8G/256G的,这两个数据分别是什么呢?实际上前面那个数值小一点的叫内存,也就是咱平时口中的运行内存,,而后面那个较大的数值呢,叫外存,也就是咱平时说的什么C盘D盘...这些磁盘。
理解了这些,再结合上图,就不难理解,从文件中读入数据会存入内存的意思了(实际上就是输入缓冲区)。
ὦἫ️文件名
一个文件要有一个唯一的文件标识,以便用户识别和引用。
文件名包含部分:文件路径文件名主干文件后缀
例如:c:\code\
有些人可能会问,为什么我没有看见文件后缀名呢?
那不妨看看下图这个选项打开了吗?
为了方便起见,文件标识常被称为文件名。
ὦἫ️文件指针
缓冲文件系统中,关键的概念是“文件类型指针”,简称“文件指针”
每个被使用的文件都在内存中开辟了一个相应的文件信息区,用来存放文件的相关信息(如文件的名字,文件状态及文件当前的位置等)。
这些信息是保存在一个结构体变量中的。该结构体类型是有系统声明的,取名FILE.
听着是不是有点懵?什么意思呢?
通俗的讲啊,这个文件指针是用来维护一块空间的,怎样的一块空间呢?是一个结构体,在stdio.h定义中被声明为FILE
看以下图解:
假设我的磁盘中有一个文件叫这样一个文件,如下图:
一旦当我打开这个文件时,他就会在内存中开辟一块文件信息区(一个结构体,类型是FILE),而FILE ptr(假设创建的变量名为ptr)这个结构体就是这个文件信息区的一块空间(如下图)
想看这个结构体的成员,可以通过VS201,(2019已经不显示了)如下:
struct _iobuf
{ char *_ptr;int _cnt;char *_base; int _flag;int _file;int _charbuf;int _bufsiz;char *_tmpfname;
};typedef struct _iobuf FILE;
刚刚提到一旦打开文件就会在内存中创建文件信息区
在C语言的程序里通过fopen这个函数可以打开文件,打开成功会后就会返回这块空间起始位置的地址,这块空间类型为FILE,所以返回的地址就是FILE*类型,程序员就可以通过创建一个FILE*的变量来维护这块空间,这就是文件指针。
下面演示一下如何创建一个指针变量
FILE* pf;//文件指针变量
定义pf是一个指向FILE类型数据的指针变量。可以使pf指向某个文件的文件信息区(是一个结构体变量)。通过该文件信息区中的信息就能够访问该文件。也就是说,通过文件指针变量能够到与它关联的文件。
如下图:
ὁ相关函数
ὦἫ️文件的打开和关闭(fopen,fclose)
咱先给出语法格式
//打开文件
FILE * fopen ( ct char * filename, ct char * mode );
//关闭文件
int fclose ( FILE * stream );
需要注意以下几点:
文件读写前要打开文件,读写后要关闭文件;
ASIC 规定使用fopen函数来打开文件,fclose来关闭文件;
在编写文件,打开文件的同时fopen会返回一个指针,若打开成功,则返回该文件在文件信息区的起始空间地址,若打开失败则返回空指针,所以我们为了防止程序出bug,因该这样写(如下代码):
#include<stdio.h>
#include<errno.h>
#include<string.h>int main()
{FILE* ptr = fopen(, w);if (ptr == ULL){printf(%s\n, strerror(errno));return 1;}//处理fclose(ptr);return 0;
}
亦或是这样写,如下(报出错误信息即可)
#include<stdio.h>
#include<errno.h>
#include<string.h>int main()
{FILE* ptr = fopen(, w);if (ptr == ULL){perror(fopen);//如果没能打开文件,perror会直接打印错误信息return 1; //括号里是可以任意写的一个常量字符串}//处理fclose(ptr);return 0;
}
这样写真的就够了吗?
想象一下,fclose可以释放带哦ptr所指向的那块空间,而一旦ptr所指向的空间被释放掉,ptr便成了野指针,所以将ptr置为空指针,如下:
#include<stdio.h>
#include<errno.h>
#include<string.h>int main()
{FILE* ptr = fopen(, w);if (ptr == ULL){perror(fopen);//如果没能打开文件,perror会直接打印错误信息return 1; //括号里是可以任意写的一个常量字符串}//处理fclose(ptr);ptr = ULL;return 0;
}
最常用的便是只读、只写,以下为代码演示:
#include<stdio.h>
#include<errno.h>
#include<string.h>int main()
{//打开文件FILE* ptr = fopen(, w);if (ptr == ULL){perror(fopen);//如果没能打开文件,perror会直接打印错误信息return 1; //括号里是可以任意写的一个常量字符串}//处理fprintf(ptr, hello world);//关闭文件fclose(ptr);return 0;
}
#include<stdio.h>
#include<errno.h>
#include<string.h>int main()
{char str[15] = { 0 };//打开文件FILE* ptr = fopen(, w);if (ptr == ULL){perror(ptr);//如果没能打开文件,perror会直接打印错误信息return 1; //括号里是可以任意写的一个常量字符串}//处理fprintf(ptr, hello world);//关闭文件fclose(ptr);//打开文件FILE* ptr_ = fopen(, r);if (ptr_ == ULL){perror(ptr_);return 1;}//处理fgets(str, sizeof(str), ptr_);printf(%s\n, str);//关闭文件fclose(ptr_);ptr_ = ULL;return 0;
}
ὦἫ️文件的顺序读写
先看看要求
怎么用呢?
格式:
int fputc( int c, FILE *stream );
c表示要输入的字符,stream表示要被输出的位置
#include<stdio.h>
#include<errno.h>
#include<string.h>int main()
{//打开文件FILE* ptr = fopen(, w);if (ptr == ULL){perror(ptr);//如果没能打开文件,perror会直接打印错误信息return 1; //括号里是可以任意写的一个常量字符串}//处理char i = 0;for (i = a ; i <= z ; i){fputc(i, ptr);}//关闭文件fclose(ptr);ptr = ULL;return 0;
}
先看看要求
怎么用呢?
格式:
int fgetc( FILE *stream );
FILE* stream 表示一个文件指针变量,stream表示流,也就是介于内存和文件信息区的输入缓存区(这里不细讲,不是本篇重点,以后会出相关博客),简而言之就是需要你刚刚打开的文件的指针,返回类型为int。
#include<stdio.h>
#include<errno.h>
#include<string.h>int main()
{//打开文件FILE* ptr = fopen(, w);if (ptr == ULL){perror(ptr);//如果没能打开文件,perror会直接打印错误信息return 1; //括号里是可以任意写的一个常量字符串}//处理char i = 0;for (i = a ; i <= z ; i){fputc(i, ptr);}//关闭文件fclose(ptr);ptr = ULL;//打开文件FILE* ptr_ = fopen(, r);if (ptr_ == ULL){perror(ptr_);return 1;}//处理int ch = 0;//要注意,fgetc返回值是int类型,所以用int来接收while ((ch = fgetc(ptr_)) != EOF)//读取完返回EOF 这里注意优先级,用括号括起来{printf(%c , ch);}//关闭文件fclose(ptr_);ptr_ = ULL;return 0;
}
先来看看要求
怎么用呢?
格式
int fputs( ct char *string, FILE *stream );
string是要被输出的常量字符串,stream是被输出的文件指针;
#include<stdio.h>
#include<errno.h>
#include<string.h>int main()
{//打开文件FILE* ptr = fopen(, w);if (ptr == ULL){perror(ptr);return 1;}//操作fputs(hehe\n, ptr);//关闭文件fclose(ptr);ptr = ULL;return 0;
}
先来看看要求
怎么用呢?
格式
char *fgets( char *string, int n, FILE *stream );
从指定的流 stream 读取一行,并把它存储在 str 所指向的字符串内。当读取 (n-1) 个字符时,或者读取到换行符时,或者到达文件末尾时,它会停止,具体视情况而定。
#include<stdio.h>
#include<errno.h>
#include<string.h>int main()
{//打开文件FILE* ptr = fopen(, w);if (ptr == ULL){perror(ptr);return 1;}//操作fputs(hehe\n, ptr);//关闭文件fclose(ptr);ptr = ULL;//打开文件FILE* p = fopen(, r);if (p == ULL){perror(p);return 1;}//操作char str[5] = { 0 };fgets(str, 5, p);printf(%s\n, str);//关闭文件fclose(p);p = ULL;return 0;
}
先看看要求
怎么用呢?
格式
int fprintf( FILE *stream, ct char *format [, argument ]...);
这里都可以对比printf的格式
int printf(ct char *format [, argument ]...);
实际不难看懂,只是多了一个被输出的文件流
#include<stdio.h>
#include<errno.h>
#include<string.h>int main()
{//打开文件FILE* ptr = fopen(, w);if (ptr == ULL){perror(ptr);return 1;}//操作文件fprintf(ptr, hello world\n);//关闭文件fclose(ptr);ptr = ULL;return 0;
}
先来看看要求
怎么用呢?
格式
int fscanf( FILE *stream, ct char *format [, argument ]... );
同理和scanf函数对比格式
int scanf(ct char *format [, argument ]... );
不难理解,也是少了文件指针流
#include<stdio.h>
#include<errno.h>
#include<string.h>int main()
{//打开文件FILE* ptr = fopen(, w);if (ptr == ULL){perror(ptr);return 1;}//操作文件fprintf(ptr, hello world\n);//关闭文件fclose(ptr);ptr = ULL;//打开文件FILE* p = fopen(, r);if (p == ULL){perror(p);return 1;}//操作文件char str[20] = { 0 };fscanf(p, %s, str);//fscanf遇到空格停止读取printf(%s , str);fscanf(p, %s, str);printf(%s\n, str);//关闭文件fclose(p);p = ULL;return 0;
}
先看看要求
怎么用呢?
格式
size_t fwrite( ct void *buffer, size_t size, size_t count, FILE *stream );
简而言之:将buffer这个任意类型,放入count个以size个字节的大小到stream
int main()
{//打开文件FILE* ptr = fopen(, w);if (ptr == ULL){perror(ptr);return 1;}//操作文件student s = { chen,19 };fwrite(&s, sizeof(s), 1, ptr);//关闭文件fclose(ptr);ptr = ULL;return 0;
}
先来看看要求
怎么用呢?
格式
size_t fread( void *buffer, size_t size, size_t count, FILE *stream );
简而言之:将stream这个文件流的count个size大小的数据写入buffer中
#include<stdio.h>
#include<errno.h>
#include<string.h>typedef struct student
{char name[15];int age;
}student;int main()
{//打开文件FILE* ptr = fopen(, w);if (ptr == ULL){perror(ptr);return 1;}//操作文件student s = { chen,19 };fwrite(&s, sizeof(s), 1, ptr);//关闭文件fclose(ptr);ptr = ULL;//打开文件FILE* p = fopen(, r);if (p == ULL){perror(p);return 1;}//操作文件student s1 = { 0 };fread(&s1, sizeof(s), 1, p);printf(%s %d\n, , s1.age);//关闭文件fclose(p);p = ULL;return 0;
}
先看看要求
怎么用呢?
格式
int fseek( FILE *stream, long offset, int origin );
简而言之:在文件stream里,以为起点origin(偏移起始位置:文件头0(SEEK_SET),当前位置1(SEEK_CUR),文件尾2(SEEK_ED)),将光标偏移offset个字符;
#include<stdio.h>
#include<errno.h>
#include<string.h>int main()
{//打开文件FILE* ptr = fopen(, w);if (ptr == ULL){perror(ptr);return 0;}//处理文件fputs(hellowcdef, ptr);fseek(ptr, 6, SEEK_SET);fputs( hello world\n, ptr);//关闭文件fclose(ptr);ptr = ULL;return 0;
}
先看看要求
怎么用呢?
格式
//未保存数据丢失//
#include<stdio.h>
#include<errno.h>
#include<string.h>int main()
{//打开文件FILE* ptr = fopen(, w);if (ptr == ULL){perror(ptr);return 0;}//处理文件fputs(world, ptr);rewind(ptr);fputs(hello\n, ptr);//关闭文件fclose(ptr);ptr = ULL;return 0;
}
被许多人误用的函数:feof用来判断文件是否结束
实际上:feof是在文件结束的时候判断文件结束的原因,判断文件是因为遇到文件位结束还是读取失败结束
- 1. 文本文件读取是否结束,判断返回值是否为EOF(fgetc),或者ULL(fgets)例如:
- fgetc判断是否为EOF.
- fgets判断返回值是否为ULL.
- 2. 二进制文件的读取结束判断,判断返回值是否小于实际要读的个数。例如:
- fread判断返回值是否小于实际要读的个数
#include <stdio.h>#include <stdlib.h>int main(void)
{int c; // 注意:int,非char,要求处理EOFFILE* fp = fopen(, r);if(!fp){perror(File opening failed);return EXIT_FAILURE;} //fgetc 当读取失败的时候或者遇到文件结束的时候,都会返回EOFwhile ((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 = ULL;return 0;
}
ὁ文本文件和二进制文件
- 文本文件
- { 以ASCII字符的形式存储的文件就是文本文件 };
- 二进制文件
- { 数据在内存中以二进制的形式存储,如果不加转换的输出到外存,就是二进制文件。 }
数据在文本文件中和在二进制文件中分别是怎么存储的?
如有整数10000,如果以ASCII码的形式输出到磁盘,则磁盘中占用5个字节(每个字符一个字节),而二进制形式输出,则在磁盘上只占4个字节。
ὁ面试题
对比一组函数
scanf/fscanf/sscanf
printf/fprintf/sprintf
scanf/prinf 是针对标准输入流/标准输出流的 格式化输入/输出
fscanf/fprintf 是针对所有输入流/所有输出流的 格式化输入/输出
sscanf/sprintf sscanf是从字符串中读取格式化的数据 sprintf是把格式化的数据输出成(存储到)字符串
码字不易~
#感谢您对电脑配置推荐网 - 最新i3 i5 i7组装电脑配置单推荐报价格的认可,转载请说明来源于"电脑配置推荐网 - 最新i3 i5 i7组装电脑配置单推荐报价格
上一篇:2020 java面试部分汇总
下一篇:JS 之 解构赋值
推荐阅读
留言与评论(共有 13 条评论) |
本站网友 南京熊猫信息产业有限公司 | 3分钟前 发表 |
ct char *format [ | |
本站网友 倩碧黄油无油 | 20分钟前 发表 |
w);if (ptr == ULL){perror(fopen);//如果没能打开文件,perror会直接打印错误信息return 1; //括号里是可以任意写的一个常量字符串}//处理fclose(ptr);return 0; } 这样写真的就够了吗? 想象一下,fclose可以释放带哦ptr所指向的那块空间,而一旦ptr所指向的空间被释放掉,ptr便成了野指针,所以将ptr置为空指针,如下: #include<stdio.h> #include<errno.h> #include<string.h>int main() {FILE* ptr = fopen( | |
本站网友 北京皮肤病 | 19分钟前 发表 |
str);//fscanf遇到空格停止读取printf(%s | |
本站网友 唇毛 | 29分钟前 发表 |
例二 #include<stdio.h> #include<errno.h> #include<string.h>int main() {//打开文件FILE* ptr = fopen( | |
本站网友 张嗣义 | 23分钟前 发表 |
下面演示一下如何创建一个指针变量 FILE* pf;//文件指针变量 定义pf是一个指向FILE类型数据的指针变量 | |
本站网友 世卫组织打脸海尔 | 8分钟前 发表 |
本站网友 炖鱼胶 | 17分钟前 发表 |
%s | |
本站网友 哈尔滨二手房网 | 4分钟前 发表 |
FILE *stream ); string是要被输出的常量字符串,stream是被输出的文件指针; 例三 #include<stdio.h> #include<errno.h> #include<string.h>int main() {//打开文件FILE* ptr = fopen( | |
本站网友 iis安装包下载 | 9分钟前 发表 |
sizeof(s) | |
本站网友 哇嘎绿色版 | 18分钟前 发表 |
r);if (p == ULL){perror(p);return 1;}//操作文件student s1 = { 0 };fread(&s1 | |
本站网友 孕妇能吃桃子吗 | 26分钟前 发表 |
sizeof(s) | |
本站网友 下一个目标是谁 | 21分钟前 发表 |
这些信息是保存在一个结构体变量中的 |