文件概述

文件几乎无处不在,主要分为磁盘文件和设备文件,典型的磁盘文件有文本文件和二进制文件,磁盘文件存储在外部存储介质(例如磁盘,硬盘,U盘等等)需要加载到内存中才能使用。
无论是文本文件还是二进制文件在计算机内部都是以字节为单位,二进制的方式存储。

  • 文本文件存储的是字符对应的ASCII码值,例如文本字符的a在计算机内部就是以二进制01100001 即97存储。当使用文本编辑器(例如Visual Studio Code)打开文本文件时,会将文本文件的二进制转换成ASCII编码对应的字符。
  • 二进制文件存和取的是二进制数值,常见的二进制文件有图片、音频、视频等等。二进制文件不能使用文本编辑器(例如Visual Studio Code)打开,图片需要使用特定的软件(例如Windows的照片浏览器)打开。

设备文件有标准输入文件(stdin),标准输出文件(stdout),标准错误(stderr)三个文件,设备文件在程序启动时由系统默认打开,程序员无需调用fopen(stdin/stdout/stderr,"r+")函数打开这三个设备文件即可使用。

  • stdin: 标准输入,默认为当前终端(键盘),我们使用的scanf、getchar函数默认从此终端获得数据。
  • stdout:标准输出,默认为当前终端(屏幕),我们使用的printf、puts函数默认输出信息到此终端。
  • stderr:标准出错,默认为当前终端(屏幕),我们使用的perror函数默认输出信息到此终端。

文件流指针

当打开文件时,系统内核会返回一个FILE结构体,该结构体有对文件操作的所有信息。

typedef struct{short           level;//缓冲区"满"或者"空"的程度 unsigned        flags;//文件状态标志 char            fd;//文件描述符unsigned char   hold;//如无缓冲区不读取字符short           bsize;//缓冲区的大小unsigned char   *buffer;//数据缓冲区的位置 unsigned        ar; //指针,当前的指向 unsigned        istemp;//临时文件,指示器short           token;//用于有效性的检查 }FILE;

而当调用fopen()函数时,系统会返回这个FILE结构体的地址,即 FILE * p; ,当使用函数fputc('a',p)往文件写入字符时,只需要传递文件流指针p即可。
文件流指针和之前的指针不同的是无法通过*p获取文件内容。

文件的打开和关闭

文件的打开

C语言提供了fopen()函数用于打开文件,该函数的声明位于stdio.h头文件中,fopen()调用时需要两个参数:路径名和打开的方式,如果是当前路径以./表示,Visual Studio2019 本地Windows调试器运行时源文件file_open_close.c的当前目录是D:workspacecittimelinedotnetvs2019c-corec-core-advanced,打开方式可以是如下几种方式

  • r或rb 以只读方式打开一个文本文件(不创建文件,若文件不存在则报错)
  • w或wb 以写方式打开文件(如果文件存在则清空文件,文件不存在则创建一个文件)
  • a或ab 以追加方式打开文件,在末尾添加内容,若文件不存在则创建文件
  • r+或rb+ 以可读、可写的方式打开文件(不创建新文件)
  • w+或wb+ 以可读、可写的方式打开文件(如果文件存在则清空文件,文件不存在则创建一个文件)
  • a+或ab+ 以添加方式打开文件,打开文件并在末尾更改文件,若文件不存在则创建文件

其中w选项如果文件不存在会创建文件,但是如果文件有内容会清空。r选项文件不存在,则不创建文件。而b表示打开二进制文件。
fopen()打开文件成功后返回FILE*p结构体的地址,也标识了那个文件,操作指针就是操作那个文件。打开失败返回NULL。

以只读的方式打开当前路径下的test.txt文件

#define _CRT_SECURE_NO_WARNINGS#include #include /*  以只读方式打开当前目录的test.txt文本文件*/void readonly_open_txt() {FILE* p_readonly = fopen("./test.txt", "r");if (p_readonly == NULL) {//追加错误提示前缀perror("readonly mode open file");return;}}/*文件的打开和关闭  fopen()函数打开方式说明 r或rb以只读方式打开一个文本文件(不创建文件,若文件不存在则报错) w或wb以写方式打开文件(如果文件存在则清空文件,文件不存在则创建一个文件) a或ab以追加方式打开文件,在末尾添加内容,若文件不存在则创建文件 r+或rb+以可读、可写的方式打开文件(不创建新文件) w+或wb+以可读、可写的方式打开文件(如果文件存在则清空文件,文件不存在则创建一个文件) a+或ab+以添加方式打开文件,打开文件并在末尾更改文件,若文件不存在则创建文件@author liuguanglei 18601767221@163.com@wechat 18601767221@website ittimeline.net@version 2020/11/29*/int file_open_close_main(int argc, char* argv[]){readonly_open_txt();system("pause");return 0;}

因为当前路径下不存在test.txt文件,所以程序运行时会出现错误提示

以只写的方式打开当前目录下的test.txt文本文件,如果文件不存在则会创建文件,打开成功返回FILE *p_write

#define _CRT_SECURE_NO_WARNINGS#include #include /* 以只写的方式打开当前目录下的test.txt文本文件,如果文件不存在则会创建文件,打开成功返回FILE *p_write*/FILE*  write_open_txt() { FILE* p_write = fopen("./test.txt", "w"); if (p_write == NULL) {  perror("write mode open file");  return; } else { printf("open test.txt success!"); } return p_write;}/*文件的打开和关闭  fopen()函数打开方式说明 r或rb以只读方式打开一个文本文件(不创建文件,若文件不存在则报错) w或wb以写方式打开文件(如果文件存在则清空文件,文件不存在则创建一个文件) a或ab以追加方式打开文件,在末尾添加内容,若文件不存在则创建文件 r+或rb+以可读、可写的方式打开文件(不创建新文件) w+或wb+以可读、可写的方式打开文件(如果文件存在则清空文件,文件不存在则创建一个文件) a+或ab+以添加方式打开文件,打开文件并在末尾更改文件,若文件不存在则创建文件@author liuguanglei 18601767221@163.com@wechat 18601767221@website ittimeline.net@version 2020/11/29*/int main(int argc, char* argv[]){FILE* p_write = write_open_txt();system("pause");return 0;}

程序运行结果

以只写方式打开时如果test.txt文件不存在,系统会创建文件

文件的关闭

C语言提供了fclose()函数用于关闭文件,该函数的声明也位于stdio.h头文件中,fclose()函数需要的参数就是打开文件返回的文件流指针,通常情况下文件打开后如果操作完成应该就要关闭。如果文件只打开而不关闭,会给程序造成异常。系统设置了一个应用程序只能打开1024个文件。

以只写的方式打开当前系统路径下的文本文件test.txt 后关闭文件

#define _CRT_SECURE_NO_WARNINGS#include #include /*以只写的方式打开当前目录下的test.txt文本文件,如果文件不存在则会创建文件,打开成功返回FILE *p_write*/FILE*  write_open_txt() {FILE* p_write = fopen("./test.txt", "w");if (p_write == NULL) {perror("write mode open file");return;}return p_write;}/*文件的打开和关闭  fopen()函数打开方式说明 r或rb以只读方式打开一个文本文件(不创建文件,若文件不存在则报错) w或wb以写方式打开文件(如果文件存在则清空文件,文件不存在则创建一个文件) a或ab以追加方式打开文件,在末尾添加内容,若文件不存在则创建文件 r+或rb+以可读、可写的方式打开文件(不创建新文件) w+或wb+以可读、可写的方式打开文件(如果文件存在则清空文件,文件不存在则创建一个文件) a+或ab+以添加方式打开文件,打开文件并在末尾更改文件,若文件不存在则创建文件@author liuguanglei 18601767221@163.com@wechat 18601767221@website ittimeline.net@version 2020/11/29*/int main(int argc, char* argv[]){FILE *p_write=write_open_txt();//关闭文件fclose(p_write);system("pause");return 0;}

文件的顺序读写

基于字符写文件

C语言提供了fputc()函数实现写入单个字符到文件中,该函数需要两个参数:字符和文件流指针。写入成功会返回写入的字符,如果写入失败则返回-1

#define _CRT_SECURE_NO_WARNINGS#include #include /*以字符的方式写入文件*/void write_file_char() {//以写的方式打开当前目录下的test.txt文件FILE* p_write = fopen("./test.txt","w");if (NULL==p_write) {perror("write mode open fail");return;}//将字符a写入当前目录下的test.txt文件char c=fputc('a', p_write);printf("写入test.txt文本文件的字符内容是%c",c);}/*基于字符的文件写操作@author liuguanglei 18601767221@163.com@wechat 18601767221@website ittimeline.net@version 2020/11/29*/int main(int argc, char* argv[]){write_file_char();system("pause");return 0;}

程序运行结果

查看当前目录D:workspacecittimelinedotnetvs2019c-corec-core-advanced 下test.txt文件的内容

需要注意的是fputc()函数在写入字符前,默认会清空文件的内容,如果要是追加文件,将打开文件的打开方式改成追加即可。

//以追加的方式打开当前目录下的test.txt文件FILE* p_append = fopen("./test.txt","a");

而如果想要往文件追加写入字符串,借助循环就可以搞定

#define _CRT_SECURE_NO_WARNINGS#include #include /*以追加的方式将字符写入test.txt文本文件中*/void append_file_str() {FILE* p_append = fopen("./test.txt", "a");if (NULL == p_append) {perror("write mode open fail");return;}//以追加的方式将字符串hello world写入test.txt文本文件中char buf[] = "hello world";int i = 0;while (buf[i] != 0) {fputc(buf[i], p_append);i++;}}/*基于字符的文件写操作@author liuguanglei 18601767221@163.com@wechat 18601767221@website ittimeline.net@version 2020/11/29*/int main(int argc, char* argv[]){append_file_str();system("pause");return 0;}

写入字符串

基于字符读文件

C语言提供了fgetc()函数实现基于字符从字符流指针中读取文件,该函数的参数只需要传递文件流指针即可,读取成功会返回读取的字符,读取失败返回-1。

#define _CRT_SECURE_NO_WARNINGS#include #include char buf[128] = "";/*读取指定路径的文件并返回char**/char * read_text_by_char(char *path) {//以只读的方式打开当前路径下的test.txt文件FILE *p_readonly=fopen(path,"r");if (NULL==p_readonly) {perror("read file error");return NULL;}int i= 0;//EOF 表示-1 即当没有读取失败时将读取的值赋值给buf[i ]//fgetc()的返回值是-1表示失败,当读取的文件中有-1时,就会提前结束,因此不能使用EOFwhile ((buf[i++] = fgetc(p_readonly)) != EOF);return &buf;}/*基于字符读取文件@author liuguanglei 18601767221@163.com@wechat 18601767221@website ittimeline.net@version 2020/11/29*/int main(int argc, char* argv[]){char *buffer=read_text_by_char("./test.txt");printf("test.txt content is %s", buffer);system("pause");return 0;}

程序运行结果

fgetc()函数在基于字符读取文件时,如果文件内容有-1这种数字,就不能使用EOF作为文件的结尾。

为了解决这个问题,C语言提供了feof()函数用于检测是否读到了文件的结尾。即判断最后一次读操作的内容不是当前位置的内容(上一个内容),该函数的返回值如果是0就表示没有到文件结尾,如果是非0就表示到文件结尾。

#define _CRT_SECURE_NO_WARNINGS#include #include char buf[128] = "";/*使用feof()函数判断文件是否读取完毕,解决了fgetc()函数读取-1字符的二进制返回-1时读取就停止的问题*/char* read_text(char * path) {//以只读的方式打开当前路径下的test.txt文件FILE* p_readonly = fopen(path, "r");if (NULL == p_readonly) {perror("read file error");return NULL;}int i = 0;int pos = 0;do {buf[i] = fgetc(p_readonly);i++;pos = feof(p_readonly);// pos ==0 表示没有到文件末尾} while (pos==0);return buf;}/*基于字符读取文件@author liuguanglei 18601767221@163.com@wechat 18601767221@website ittimeline.net@version 2020/11/29*/int main(int argc, char* argv[]){char *buffer=read_text("./test.txt");printf("test.txt content is %s", buffer);system("pause");return 0;}

基于字符文件的拷贝

文件的拷贝就是将一个文件创建一个副本。
而文本文件的拷贝的实现过程就是首先读取一个文件,然后将读取的文件内容写入到待拷贝的文件中。

我这里封装了一个函数 copy_text_file(char* source_path,char *target_path) ,只需要传递源文件和目标文件就可以实现文件的拷贝

#define _CRT_SECURE_NO_WARNINGS#include #include /*封装一个文本文件的拷贝方法,传递两个文件的路径实现将source_path的文件内容拷贝到target_path*/void copy_text_file(char* source_path,char *target_path) {FILE* source = fopen(source_path,"r");if (NULL == source) {perror("open file  error");}FILE* target = fopen(target_path,"w");if (NULL == target) {perror("open file target.txt error");}char ch = 0;while (1) {//读取文件的内容ch=fgetc(source);//读取到函数的末尾if (feof(source)) {break;}//将读取的文件内容写入到target文件指针fputc(ch, target);}//关闭文件fclose(target);fclose(source);}/*实现文件拷贝@author liuguanglei 18601767221@163.com@wechat 18601767221@website ittimeline.net@version 2020/11/29*/int main(int argc, char* argv[]){copy_text_file("./test.txt","./target.txt");system("pause");return 0;}

程序运行结果
查看拷贝的源文件和目标文件的内容

但是copy_text_file(char* source_path,char *target_path)函数只能实现文本文件的拷贝,如果想要实现二进制文件(例如图片)的拷贝,需要稍微改造下fopen()方法

#define _CRT_SECURE_NO_WARNINGS#include #include /*二进制文件的复制*/void copy_binary_file(char* source_path, char* target_path) {FILE* source = fopen(source_path, "rb");if (NULL == source) {perror("open file  error");}FILE* target = fopen(target_path, "wb");if (NULL == target) {perror("open file target.txt error");}char ch = 0;while (1) {//读取文件的内容ch = fgetc(source);//读取到函数的末尾if (feof(source)) {break;}//将读取的文件内容写入到target文件指针fputc(ch, target);}//关闭文件fclose(target);fclose(source);}/*实现文件拷贝@author liuguanglei 18601767221@163.com@wechat 18601767221@website ittimeline.net@version 2020/11/29*/int main(int argc, char* argv[]){copy_binary_file("./20201129.jpg","./20201129_copy.jpg");system("pause");return 0;}

程序运行结果

基于字符的文件查看

将指定的文件内容写入到终端

#define _CRT_SECURE_NO_WARNINGS#include #include void cat_file(char* file_path) {//以只读方式打开当前目录的text_file_cat.c文件FILE *p=fopen(file_path,"r");if (NULL==p) {perror("file read error");return;}char ch = 0;while (1) {//读取指定的内容ch = fgetc(p);//如果读到文件末尾if (feof(p)) {break;}//将读取的文件内容写入到终端 //stdout表示终端的文件流指针//printf()底层会调用fputc()fputc(ch,stdout);}//关闭文件fclose(p);}/*文本文件查看@author liuguanglei 18601767221@163.com@wechat 18601767221@website ittimeline.net@version 2020/11/29*/int main(int argc, char* argv[]){cat_file("text_file_cat.c");return 0;}

程序运行结果

基于行写文件

C语言提供了fputs(const char*str,FILE *stream)函数用于将字符串写入到指定的文件,其中str是待写入文件的字符串地址,stream表示文件流指针,字符串结束符 '0' 停止写入,写入成功返回0,写入失败返回-1。

#define _CRT_SECURE_NO_WARNINGS#include #include /*fputs()写入字符串到指定的文件@author liuguanglei 18601767221@163.com@wechat 18601767221@website ittimeline.net@version 2020/11/29*/int main(int argc, char* argv[]){//以只写的方式打开当前路径下的test.txtFILE* p = fopen("test.txt","w");if (NULL==p) {perror("open file fail");}char buf[] = "I will see you again0again ";//将字符串I will see you again 写入到test.txt文件中//遇到0停止写入int result = fputs(buf,p);if (result==0) {printf("写入数据成功");}else {printf("写入数据失败");}system("pause");return 0;}

程序运行结果

基于行读文件

C语言提供了fgets(char* str, int size ,FILE *stream)函数用于从文件读取字符串,其中str用于保存读取的内容,而size是指定最大读取字符串的长度(size-1),stream表示文件流指针。fgets()函数遇到会结束。
读取成功则返回读取的字符串,读取到文件末尾或则失败则返回NULL。需要注意的是 fgets()函数只能操作字符串,不能操作二进制文件。

#define _CRT_SECURE_NO_WARNINGS#include #include /*基于fgets()读取指定文件的字符串@author liuguanglei 18601767221@163.com@wechat 18601767221@website ittimeline.net@version 2020/11/29*/int main(int argc, char* argv[]){FILE* p = fopen("./test.txt", "r");if (NULL == p) {perror("读取文件错误");return;}char buf[1024] = "";fgets(buf, sizeof(buf), p);printf("buf = %s ", buf);system("pause");return 0;}

程序运行结果

基于fputs()函数和fgets()函数实现的文本文件拷贝

#define _CRT_SECURE_NO_WARNINGS#include #include #include /*基于fputs()和fgets()函数实现的文件拷贝 只能支持文本文件,因为遇到0会停止读写*/void copy_by_fgets_fputs(char * source_path,char *target_path) {FILE* source = fopen(source_path,"r");if (NULL==source) {perror("open file fail");return;}FILE* target = fopen(target_path,"w");if (NULL == target) {perror("open file fail");return;}char* p = NULL;//循环多少次,buf就可以使用多少次char buf[1024] = "";while (1) {memset(buf, 0, sizeof(buf));p = fgets(buf, sizeof(buf), source);//读取结束if (p==NULL) {break;}//将读取的内容写入到targetfputs(buf, target);}//fclose(target);fclose(source);}/*基于fputs()和fgets()函数实现的文件内容拷贝@author liuguanglei 18601767221@163.com@wechat 18601767221@website ittimeline.net@version 2020/11/29*/int main(int argc, char* argv[]){copy_by_fgets_fputs("./test.txt","./copy_of.txt");system("pause");return 0;}

程序运行结果

基于文件读写实现随机生成表达式并完成四则运算

首先定义一个宏,用于描述生成表达式的数量

//表达式生成的数量#define EXPRESSION_NUM 10

由于生产表达式,需要读写文件,在读写文件之前,需要打开文件,因此封装一个打开文件的函数,该函数需要一个参数:打开方式
而FILE_PATH 也是宏定义的文件路径#define FILE_PATH "expression_calc.txt",算术运算表达式就是存储在该文件中。

/*按照指定的打开方式打开指定路径的文件*/FILE* open_file(char * mode) {FILE* fp=fopen(FILE_PATH, mode);if (NULL==fp) {perror("open file fail");return;}return fp;}

然后实现生成表达式的函数。以及将生成的表达式写入文件中。
这其中表达式的操作数和运算符都是是随机生成的,需要借助srand()函数和rand()函数。
然后还要使用sprintf()函数组包生成表达式。

/*生成表达式并写入文件*/void generator_expression_write_file() {FILE *fp=open_file("w");//设置随机种子srand(time(NULL));int left = 0;int right = 0;char opertors[4] = {'+','-','*','/'};char operator_index=0;char singleton_expression[128] = "";//生成10个随机表达式字符串for (int i = 0; i < EXPRESSION_NUM;i++) {//产生1-100之间的随机数left= rand()%100+1;right= rand()%100+1;//产生0-3之间的随机数赋值给operator_indexoperator_index =rand() % 4;//将 "%d %c %d = ",left, opertors[operator_index],right 赋值给expressionsprintf(singleton_expression,"%d%c%d=",left, opertors[operator_index],right);fputs(singleton_expression, fp);}fclose(fp);}

然后实现读取文件后计算表达式,并将表达式的结果写入FILE_PATH中。

/*计算表达式的结果并写入文件*/void calc_expression_write_file() {FILE* fp = open_file("r");//第一个操作数int left = 0;//第二个操作数int right = 0;//运算符char operator=0;//运算的结果int result = 0;//读取的单个表达式(未计算)char buf[128] = "";//单个表达式(已经计算结果的)char singleton_expression[128] = "";//所有的表达式char all_expression[100][128] = { 0 };//读取一行表达式的指针char* p = NULL;int i = 0;printf("生成的表达式列表");while (1) {//每次读取一行p = fgets(buf, sizeof(buf), fp);if (p == NULL) {break;}//将读取的内容buf 解析到left, operator,right变量中sscanf(buf, "%d%c%d", &left, &operator,&right);//根据运算的符来进行运算并保存运算的结果switch (operator) {case '+':result = left + right;break;case '-':result = left - right;break;case '*':result = left * right;break;case '/':result = left + right;break;}//2+3=5//将表达式以及计算的结果写入all_expression二维数组中sprintf(all_expression[i], "%d%c%d=%d", left, operator,right, result);printf("%s ",  all_expression[i]);i++;}//关闭文件fclose(fp);//FILE *n_fp = open_file("w");for (int j = 0; j < i; j++) {int result =fputs(all_expression[j], n_fp);if (result==0) {printf("写入%s到文件%s成功", all_expression[j],FILE_PATH);}else {printf("写入%s到文件%s失败", all_expression[j], FILE_PATH);}}fclose(n_fp);}

最后在main函数中依次调用这两个函数并运行即可

#define _CRT_SECURE_NO_WARNINGS#include#include#include#include //表达式生成的数量#define EXPRESSION_NUM 10#define FILE_PATH "expression_calc.txt"/*基于文件读写实现随机生成表达式并完成四则运算@author liuguanglei 18601767221@163.com@wechat 18601767221@website ittimeline.net@version 2020/11/29*/int main(int argc, char* argv[]){generator_expression_write_file();calc_expression_write_file();system("pause");return 0;}

程序运行结果

程序运行结果

基于指定格式写文件

C语言提供了fprintf(FILE * stream, const char * format, ...)函数用于将数据按照指定的格式写入到指定的文件中,其中stream表示文件流指针,而format就是数据的格式,...表示需要组装的数据列表。
fprintf()函数写入成功则会返回实际写入的字符个数,如果写入失败则返回-1。

#define _CRT_SECURE_NO_WARNINGS#include #include /*fprintf()函数按照指定的格式写入数据到文本文件@author liuguanglei 18601767221@163.com@wechat 18601767221@website ittimeline.net@version 2020/11/29*/int main(int argc, char* argv[]){char name[] = "刘光磊";double height = 178.00;int age = 28;FILE* fp = fopen("./info.txt","w");if (NULL==fp) {perror("read file fail");return -1;}fprintf(fp, "我的名字是%s我的身高是%.2lf我的年龄是%d", name, height, age);fclose(fp);system("pause");return 0;}

程序运行结果

程序运行结果

基于指定格式读文件

C语言提供了fscanf(FILE * stream, const char * format, ...);函数用于从文件中按照指定的格式来读取数据,读取成功返回成功转换参数的个数,失败返回-1。

#define _CRT_SECURE_NO_WARNINGS#include #include /*使用fscanf()从文件中读取指定格式的数据@author liuguanglei 18601767221@163.com@wechat 18601767221@website ittimeline.net@version 2020/11/29*/int main(int argc, char* argv[]){int year = 0;int month = 0;int day = 0;FILE* fp = fopen("./date.txt", "r");if (NULL == fp) {perror("read file fail");return -1;}//从date.txt文件中读取日期并赋值给year,month,dayfscanf(fp, "%d-%d-%d", &year, &month, &day);printf("year = %d",year);printf("month = %d", month);printf("day = %d", day);system("pause");return 0;}

读取的文件内容

程序运行结果

基于块写文件

在读写大文件时需要基于块来读写文件,C语言提供了fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);函数来基于块写文件,其中ptr表示写入文件数据的地址,size表示写入文件内容的大小,nmemb表示写入文件的块数,写入文件的总大小为szie * nmemb,stream表示已经打开的文件流指针。写入成功则返实际成功写入文件数据的块数目,该值和nmemb相等。

将结构体数组user_array以块的形式写入fwrite.txt文件

#define _CRT_SECURE_NO_WARNINGS#include #include //定义一个结构体user,别名是userstypedef struct user {int id;char name[16];}users;/*fwrite()函数:基于块写文件@author liuguanglei 18601767221@163.com@wechat 18601767221@website ittimeline.net@version 2020/11/29*/int main(int argc, char* argv[]){//初始化一个结构体数组users user_array[3] = { {1,"tony"},{2,"mengmeng"},{3,"xiaohuihui"} };FILE* fp = fopen("fwrite.txt","w");if (NULL==fp) {perror("open file fail");return -1;}//fwrite()第二个参数写1,返回值刚好是写入文件的字节数int byte_size=fwrite(user_array, 1, sizeof(user_array), fp);printf("写入文件的字节数是%d",byte_size);system("pause");return 0;}

基于块读文件

C语言提供了size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);函数用于基于块的方式读取文件内容
其中ptr:存放读取出来数据的内存空间,size: size_t 为 unsigned int类型,此参数指定读取文件内容的块数据大小,nmemb:读取文件的块数,读取文件数据总大小为:size * nmemb,stream:已经打开的文件指针
如果读取成功则返回实际成功读取到内容的块数,如果此值比nmemb小,但大于0,说明读到文件的结尾。否则失败返回0

实现读取fwrite.txt文件的内容,由于该文件的内容是一个结构体数组,因此需要在头文件user.h中定义一个通用的结构体,其他的源文件使用该结构体时包含#include "user.h"即可

#pragma once//定义一个结构体user,别名是userstypedef struct user {int id;char name[16];}users;

然后使用fread()函数读取文件内容并存储到结构体数组中,然后遍历结构体数组的内容,显示在终端上。

#define _CRT_SECURE_NO_WARNINGS#include #include #include "user.h"#include /*fread()基于块的方式读取文件@author liuguanglei 18601767221@163.com@wechat 18601767221@website ittimeline.net@version 2020/11/29*/int main(int argc, char* argv[]){users user_array[3];//将数组清零memset(user_array, 0, sizeof(user_array));int size = sizeof(user_array) / sizeof(user_array[0]);FILE* fp = fopen("./fwrite.txt","r");//一次性读到user_arrayfread(&user_array, 1, sizeof(user_array), fp);for (int i = 0; i < size;i++) {//从fp读取一个结构体users并赋值给&user_array[i]//fread(&user_array[i], 1, sizeof(users), fp);printf("id = %d name = %s ",user_array[i].id,user_array[i].name);}system("pause");return 0;}

程序运行效果

文件的随机读写

之前介绍的读写文件函数都是顺序读写的。

C语言提供了fseek(FILE *stream, long offset, int whence) 函数实现移动文件流(文件光标)的读写位置实现随机读写。

  • fseek(fp,6,SEEK_SET)表示光标相对于开头向后移动6个字节
  • fseek(fp,0,SEEK_SET)表示光标移动至开头
  • fseek(fp,4,SEEK_CUR)表示光标相对当后移动4个字节
  • fseek(fp,-4,SEEK_CUR)表示光标相对当前移动4个字节
  • fseek(fp,4,SEEK_END)表示光标相对末尾往后移动4个字节

除此以外C语言还提供了rewind(fp)函数将光标移到开头,等价于fseek(fp,0,SEEK_SET),ftell(fp)函数可以获取文件流(文件光标)的读写位置。

#define _CRT_SECURE_NO_WARNINGS#include #include #include /*fseek()随机读写@author liuguanglei 18601767221@163.com@wechat 18601767221@website ittimeline.net@version 2020/11/29*/int main(int argc, char* argv[]){FILE* fp = fopen("fseek.txt", "w");if (NULL == fp) {perror("open file fail");return 0;}//往fseek.txt文件写入this is test content 此时光标默认在末尾fputs("this is test content", fp);//移动光标到首部fseek(fp, 0, SEEK_SET);//写入seek到fseek.txt,此时文件内容是seek is test contentfputs("seek", fp);//移动光标到倒数第五个字节fseek(fp,-5,SEEK_END);//在倒数第五个字节的光标写入again,此时文件内容是seek is test coagainfputs("again", fp);//将光标移到开头//rewind(fp);//将光标移到末尾fseek(fp, 0, SEEK_END);    //计算末尾到开头的字节数int byte_size=ftell(fp);printf("byte_size=%d",byte_size);int count = ftell(fp);system("pause");return 0;}

程序运行结果

获取文件信息

C语言提供了stat(const char *path, struct stat *buf)函数用于获取文件信息,如果获取成功返回0,获取失败则返回-1。stat()函数可以判断该文件存不存在获取文件状态。

在使用该函数前需要包含两个系统路径下的头文件:sys/types.h和sys/stat.h

#define _CRT_SECURE_NO_WARNINGS#include #include #include #include /*stat()函数获取文件状态@author liuguanglei 18601767221@163.com@wechat 18601767221@website ittimeline.net@version 2020/11/29*/int main(int argc, char* argv[]){//定义stat结构体struct stat file_info;int info= stat("fwrite.txt",&file_info);//文件不存在if (info<0) {//打印输出提示信息printf("file not found ");}else {printf("获取文件信息: 文件大小是%d字节 ", file_info.st_size);}system("pause");return 0;}

程序运行结果

文件删除和重命名

文件删除

C语言提供了库函数remove(const char *path)来删除一个文件,参数需要一个文件的路径,删除成功返回0,删除失败返回-1

#define _CRT_SECURE_NO_WARNINGS#include #include /*文件删除@author liuguanglei 18601767221@163.com@wechat 18601767221@website ittimeline.net@version 2020/11/29*/int main(int argc, char* argv[]){//删除当前路径下的fwrite.txt文件int flag=remove("fwrite.txt");if (flag==0) {printf("删除成功");}else {printf("删除失败");}system("pause");return 0;}

程序运行结果

文件重命名

C语言提供了rename(const char *oldpath, const char *newpath)函数实现文件的重命名,该函数需要两个文件的完整路径

#define _CRT_SECURE_NO_WARNINGS#include #include /*rename()函数实现文件的重命名@author liuguanglei 18601767221@163.com@wechat 18601767221@website ittimeline.net@version 2020/11/29*/int main(int argc, char* argv[]){//文件重命名rename("fseek.txt","fseek_rename.txt");system("pause");return 0;}

程序运行结果

Linux和Windows文本文件的区别

  • Windows字符串中带时存取的是
  • Linux中字符串带时存取的是
    如果把Windows的文本文件传到Linux系统上时使用编辑器打开会多了一个。而Linux的文本文件到Windows下就没有换行。

文件缓冲区

缓冲区本质就是内存中的一块临时空间,

当写入文件时,库函数会去调用内核提供的系统调用,例如fwrite()函数最终会调用write()系统调用。如果是大量频繁的写操作,会从用户空间切换到内核空间,上下文的切换会导致程序效率非常低。
因此引入了文件的缓冲区,当缓冲区满了才会一次性写入文件,或者有特殊场景可以调用fflush()强制刷新缓冲区,也就是将缓冲区的内容写入文件,或者程序正常退出(关闭Visual Studio的终端)时也会将缓冲区的文件写入磁盘文件。

#define _CRT_SECURE_NO_WARNINGS#include #include /*文件缓冲区@author liuguanglei 18601767221@163.com@wechat 18601767221@website ittimeline.net@version 2020/11/29*/int main(int argc, char* argv[]){FILE* fp = fopen("data.txt","w");if (NULL==fp) {perror("open file fail");return -1;}//当不关闭终端时data.txt文件没有内容fputs("this is test content ",fp);system("pause");return 0;}

缓冲区

刷新缓冲区的两种编码实现

#define _CRT_SECURE_NO_WARNINGS#include #include #include /*文件缓冲区@author liuguanglei 18601767221@163.com@wechat 18601767221@website ittimeline.net@version 2020/11/29*/int main(int argc, char* argv[]){FILE* fp = fopen("data.txt","w");if (NULL==fp) {perror("open file fail");return -1;}//当不关闭终端时data.txt文件没有内容fputs("this is test content ",fp);//可以调用fflush()函数实现强制刷新缓冲区的内容到data.txt;fflush(fp);//也可以将缓冲区写满char buf[1024] = "";//写入1M的1for (int i = 0; i < 1024;i++) {memset(buf, '1', sizeof(buf));fwrite(buf, 1, sizeof(buf), fp);}system("pause");return 0;}

而Windows下的stdout 是没有缓冲区的,即使用printf()函数打印数据到终端时不会进入缓冲区,直接写入到终端上。而Linux下的stdout文件是有缓冲区的。
Windows下标准输入(stdin) 不能调用fflush()强制刷新。

microstation添加txt文件_C开发实战-文件操作相关推荐

  1. python读文件和写文件-python开发--从文件中读取数据和写入文件

    #! /usr/bin/env python -*- coding:utf-8 -*- """ @Author:gcan @Email:1528667112@qq.com ...

  2. 请求分页内存管理的模拟 c++代码_C开发实战-内存管理

    作用域和变量 作用域就是作用的范围,当定义变量时不同作用域的变量位于不同的内存空间. 变量按照不同的作用域可以分为局部变量和全局变量.而局部变量和全局变量都可以使用static修饰,static修饰的 ...

  3. c++ 读文件_C语言处理文件基础知识:文件、流和键盘输入

    文件是一块存储信息的存储器区域,可能这样说很多同学不理解,通俗来说,就是在磁盘上划分一块区域用于存放特定的数据,比如文本数据就是文本文件,音频数据就是音频文件.当然,文件夹也是一个特殊的文件.通常,文 ...

  4. c#怎么读htm文件_c#怎么读写文件和获取文件的扩展名

    P rotected void Write_Txt(stri ng FileName, stri ng Con te nt) { En codi ng code = En codi ng.GetE n ...

  5. c语言头文件和源文件_C语言头文件防卫式声明

    C语言一般提供三种预处理功能:宏处理.文件包含.条件编译.头文件防卫式申明中会用到条件编译中 #ifndef.#define.#endif 的用法.所以,首先价绍下条件编译. 1 条件编译 一般情况下 ...

  6. 如何创建CSR文件 Apple开发 csr文件

    转自:https://jingyan.baidu.com/article/48b37f8d3bb59e1a646488f0.html 在创建Apple开发的各种证书时有时候会要求我们上传CSR文件 来 ...

  7. c++ char*初始化_C开发实战-深入理解指针

    Visual Studio 2019 解决方案的多项目应用 在讲述变量,数据类型,运算符和表达式以及程序流程控制,数组,函数的相关内容,所有的代码都放在解决方案c-core的c-core-founda ...

  8. c++ map中用char数组_C开发实战-指针和字符串

    指针操作字符数组 首先定义一个字符数组char_array,该数组占据11个字节,因为初始化值是字符串常量,而字符串常量以0结尾 char char_array[] = "helloworl ...

  9. 《崔庆才Python3网络爬虫开发实战教程》学习笔记(5):将爬虫爬取到的数据存储到TXT,Word,Excel,Json等文件中

    本篇博文是自己在学习崔庆才的<Python3网络爬虫开发实战教程>的学习笔记系列,此套教程共5章,加起来共有34节课,内容非常详细丰富!如果你也要这套视频教程的话,关注我公众号[小众技术] ...

最新文章

  1. x=a%pq与x=a%p,x=a%q的关系(pq互质)
  2. 请问 CType和DirectCast函数有何区别
  3. 【iOS开发必备指南合集二】申请IDP/真机调试/GameCenter 指南/OpenFeint指南
  4. 无任何网络提供程序接受指定的网络路径
  5. split-lapply-cbind模式--R语言
  6. Memory for crash kernel (0x0 to 0x0) notwithin permissible range
  7. 电脑怎么在线录制屏幕声音,如何内录
  8. Matlab 和 Simulink 学习基础入门
  9. 计算机网络:家庭无线网组建方案
  10. Esp8266 进阶之路33【大神篇】如何优雅地像乐鑫原厂封装esp8266底层寄存器的逻辑思维,做成自己的静态库库文件,让第三方人使用?
  11. 彩色matlab代码拷贝到word研究,matlab编辑器合并_彩色MATLAB代码拷贝到WORD研究
  12. 基于XGBoost 的机器学习可解释性
  13. C语言函数嵌套定义问题
  14. android11.0 Launcher3 高端定制之循环滑动
  15. 南京大学与东南大学的计算机,南京大学和东南大学对比分析报告
  16. 一个小工具——随机产生汽车车牌号的Java实现
  17. Honeycomb - 调试复杂系统的工具
  18. 如何发现网络中的设备 设备发现协议(收集)
  19. 大banner的源代码怎么写,超简单!
  20. X线计算机体层扫描等级,x线计算机体层(CT)扫描(使用螺旋扫描)是什么意思

热门文章

  1. 使用IPFS集群搭建创建私有IPFS网络
  2. Log4j.properties的简单配置
  3. Python可视化神器之pyecharts
  4. 介词for和with 和of的用法_英语中的for,to,at,of,in,on,with的用法
  5. 00600 ora 关闭oracle_Oracle集群高可用故障切换
  6. 尤其是java程序员(转载)_JAVA程序员 学习任务(转载)
  7. java重定向cookie_response请求转发和重定向,cookie
  8. ios查看线程数量_关于iOS多线程,你看我就够了(已更新)
  9. 苹果验证电子邮件地址服务器错误,苹果7P账户申请,验证电子邮件地址创建新Apple ID发生未知错误...
  10. win10系统预览体验计划错误代码0x800bfa19怎么办