文件操作函数(C语言)!
这篇文章主要来总结一下有关文件操作的有关函数,整片文章将按照以下内容进行说明:
目录
1. 什么是文件?
2. 为什么要使用文件
3. 文件的打开与关闭
4. 文件打开与关闭的实例
5. 文件的顺序读写
5.1.fputc
5.2 fputs
5.3 fprintf
5.4 fwrite
6. 文件的随机读写
6.1 fseek
6.2 ftell
6.3 rewind
7. 文件读取结束的判定方法
7.1 feof函数的具体作用
1. 什么是文件?
在生活中,有许许多多的文件存在,比如电脑硬盘上的文件,而我们这里所说的文件,都是指程序设计中的文件,同时,这里按功能分又大致分为两种 — 程序文件和数据文件。
程序文件:
比如我们所写的源程序文件(后缀为.c),目标文件(后缀为.obj)和可执行文件(后缀为.exe)等。
数据文件:
这种文件的内容是程序运行时读写的数据,比如程序运行需要从中读取数据的文件,或者输出内容的文件等。
注意:在这一篇文章中,我们所探讨的文件都是数据文件,并且,就是介绍怎样从硬盘上的文件中读取内容或写内容到硬盘上去。
每个文件都会有它的文件名,文件名包含3部分 — 文件路径+文件名主干+文件后缀。
文件名的作用就是为了让用户识别和引用。
2. 为什么要使用文件
有时我们在写一个存放数据的程序时,我们希望的是即使程序停止了,但它里面的数据也不会丢失,这样下次重新运行程序时,就可以查询上次的数据。所以为了实现这种功能,我们就可以把数据放到文件里面,或者静态库里,这样就做到了数据的保存,也就是数据的持久化。
总结:文件的作用主要是为了数据的持久化。
3. 文件的打开与关闭
在C语言中两个函数专门用来打开或关闭文件。
打开文件:
//函数声明
FILE *fopen( const char *filename, const char *mode );
这里推荐一个网站 —— cplusplus.com - The C++ Resources Network
通过在网站阅读有关这个函数的内容,我们可以知道,这个函数有两个参数 :
filename :从英文名上,就可以大致看出这里需要的是需要打开文件的文件名。
mode : 这个是需要以怎样的方式打开文件,这是需要我们根据自己的需求来确定的。
以下是几个常用的打开方式(mode):
最后就是返回类型 FILE* 类型的指针:
说明,我们只要成功的打开了文件,那么这个函数(fopen)就会给我们返回一个指向这个文件的FILE* 类型的指针。
一旦打开失败,我们通过以下这句话也可以知道,会给我们返回一个空指针(NULL)。
补充:每一个文件在打开后都有一个文件信息区,里面存放了有关这个文件的许多信息(文件名、文件状态及文件当前的位置等),这些信息都是保存在一个结构体变量中,并且该结构体类型是有系统声明的,取名FILE,所以打开文件函数(fopen)才会给我们返回一个FILE*类型的指针,从而让我们对该文件进行一系列操作。
注意:以上的文件信息区的内容都是系统自动填充的,我们不必过多关心里面的内容是什么。
关闭文件:
文件被打开使用完之后,肯定是要主动关闭的,这里C语言也给我们提供了一个文件关闭函数 —— fclose
//函数声明
int fclose( FILE *stream );
这个函数就比较简单了,它只有一个参数:
stream :把需要关闭文件的 FILE* 类型的指针传给它就行了。
同时这个函数也是有返回值的,成功关闭,返回一个0,遇到错误,返回EOF(-1)。
注意:在使用完fclose函数之后,我们需要把它给置为空指针(NULL),从而避免野指针的出现。
4. 文件打开与关闭的实例
#include<stdio.h>
int main()
{//以只写的模式打开文件FILE* pf = fopen("data.txt", "w");//判断是否打开成功if (NULL == pf){//打印一下错误信息perror("fopen");//结束程序return -1;}//使用...//这里先不做介绍,下面将具体举例怎么使用//关闭文件 - 一般只需要在打开文件时判断一下是否成功fclose(pf); pf = NULL; //置为空指针return 0;
}
运行程序过后,我们就能在这个程序的同目录下面找到一个空的.txt文件。
当然,如果需要打开的文件在别的目录下的话,我们也可以在使用fopen函数时,把文件的具体路径给写下来就可以了。
//也可以这样写出具体路径
FILE* pf = fopen("F:\\Git\\test\\data.txt", "w");
//注意转移字符的存在,需要使用两个\
5. 文件的顺序读写
这里的函数有如下:
这里就分别介绍一下 fputc 、fputs、fprintf 和 fwrite 写的操作。
5.1.fputc
函数声明:
int fputc( int c, FILE *stream );
函数实例:
#include<stdio.h>
int main()
{//以只写的模式打开文件FILE* pf = fopen("data.txt", "w");//判断是否打开成功if (NULL == pf){//打印一下错误信息perror("fopen");//结束程序return -1;}//写文件fputc('H', pf); //一个字符一个字符写入fputc('e', pf);fputc(108, pf);fputc('l', pf);fputc(111, pf);//关闭文件 - 一般只需要在打开文件时判断一下是否成功fclose(pf);pf = NULL; //置为空指针return 0;
}
运行后文件里的内容:
小结:该字符函数比较简单,就是往文件里一个一个字符的写入字符。
5.2 fputs
函数声明:
int fputs( const char *string, FILE *stream );
参数和 fputc 大同小异,只是从单个字符变成了一行字符串。
函数实例:
#include<stdio.h>
int main()
{//以只写的模式打开文件FILE* pf = fopen("data.txt", "w");//判断是否打开成功if (NULL == pf){//打印一下错误信息perror("fopen");//结束程序return -1;}//写文件char str[] = "hello world";fputs("Hello world!\n", pf);fputs(str, pf);//关闭文件 - 一般只需要在打开文件时判断一下是否成功fclose(pf);pf = NULL; //置为空指针return 0;
}
运行后文件内容:
从这里,我们可以看到这个函数,相较于 fputc 函数,无疑更加方便。让我们可以一句一句的写入。
5.3 fprintf
函数声明:
int fprintf( FILE *stream, const char *format [, argument ]...);
此函数的作用就是,有格式的写入数据到文件里去。函数参数分析如下:
首先,我们来对比一下printf函数的参数:
//printf函数声明
int printf( const char *format [, argument]... );//fprintf函数声明
int fprintf( FILE *stream, const char *format [, argument ]...);
我们会发现,这两个参数只有一个地方不同,就是fprintf函数多了一个FILE* 类型的指针,我们知道在对文件操作时总会用到文件指针,那么FILE* stream这个参数就是传文件指针的。然后我们通过对printf函数的用法分析,就能很轻易的知道fprintf的用法了。
函数实例:
#include<stdio.h>
int main()
{//以只写的模式打开文件FILE* pf = fopen("data.txt", "w");//判断是否打开成功if (NULL == pf){//打印一下错误信息perror("fopen");//结束程序return -1;}//写文件char str[] = "hello world!\n";int a = 100;char w = 'A';fprintf(pf, "%s%d %c", str, a, w);//关闭文件 - 一般只需要在打开文件时判断一下是否成功fclose(pf);pf = NULL; //置为空指针return 0;
}
运行后文件里的内容:
这里有个函数和它长得很像 —— sprintf(将格式化数据转化为字符串)
函数申明:
int sprintf( char *buffer, const char *format [, argument] ... );
从参数可以看到就是在printf函数的参数上加了一个char* buffer参数,用来接收字符串的地址。
实例:
#include<stdio.h> int main() {char str[200] = { 0 };int a = 100;float b = 3.14f;sprintf(str, "%d %f", a, b);printf("%s\n", str); //打印str中的字符串return 0; }
运行结果:
5.4 fwrite
函数声明:
size_t fwrite( const void *buffer, size_t size, size_t count, FILE *stream );
参数分析:
通过一下文字我们可以很清楚的知道这些参数是什么:
函数实例:
#include<stdio.h>
int main()
{//以只写的模式打开文件FILE* pf = fopen("data.txt", "wb");//判断是否打开成功if (NULL == pf){//打印一下错误信息perror("fopen");//结束程序return -1;}//写文件int a = 10000;fwrite(&a, 4, 5, pf); //将a中的值以二进制方式写入文件,并且写5次//关闭文件 - 一般只需要在打开文件时判断一下是否成功fclose(pf);pf = NULL; //置为空指针return 0;
}
运行后文件内容:
会发现,上面的内容不是5个10000,而是一串我们看不懂的内容,很正常,因为这是用二进制表达的。
6. 文件的随机读写
随机具体是指,我们想它在哪个位置读写,就从哪个位置读写,而不是字面意思的随机。
这里介绍三个指针定位函数:
6.1 fseek
函数声明:
int fseek( FILE *stream, long offset, int origin );
参数介绍:
FILE* stream :文件指针
long offset :偏移量
int origin :从哪个位置开始偏移,这里具体有三个。如下:
SEEK_CUR
Current position of file pointer —— 文件指针的当前位置
SEEK_END
End of file —— 文件的末尾
SEEK_SET
Beginning of file —— 文件的起始位置
函数实例:
#include<stdio.h>
int main()
{//打开文件FILE* pf = fopen("data.txt", "r");if (NULL == pf){perror("fopen");return -1;}//定位文件指针fseek(pf, 6, SEEK_SET);//读文件char ret = fgetc(pf); //当前文件里的内容:hello worldprintf("%c\n", ret);//关闭文件fclose(pf);pf = NULL;return 0;
}
运行结果:
这时可以看到打印出了字符w,正好它相对于起始位置的偏移量就是6。
6.2 ftell
函数声明:
long ftell( FILE *stream );
此函数参数只有一个,FILE* 类型的文件指针。函数的具体作用根据它的返回值文档介绍,简单的说就是返回文件指针相对于起始位置的偏移量。故返回值为long。
函数实例:
#include<stdio.h>
int main()
{//打开文件FILE* pf = fopen("data.txt", "r");if (NULL == pf){perror("fopen");return -1;}//文件里面有一个:hello world//定位文件指针 —— 相对于起始位置的偏移量为6fseek(pf, 6, SEEK_SET);//返回当前文件指针相对于起始位置的偏移量long number = ftell(pf);printf("%d\n", number);//关闭文件fclose(pf);pf = NULL;return 0;
}
运行结果:
观察结果,正好和上面我们主动的偏移量一致。
6.3 rewind
函数声明:
void rewind( FILE *stream );
只有一个参数 —— 文件指针。
函数具体功能,通过阅读文章可以发现此函数是将文件指针重新移动到文件的起始位置。
函数实例:
#include<stdio.h>
int main()
{//打开文件FILE* pf = fopen("data.txt", "r");if (NULL == pf){perror("fopen");return -1;}//文件里面有一个:hello world//定位文件指针fseek(pf, 6, SEEK_SET);char ret = fgetc(pf);printf("%c\n", ret);//使用rewind函数,将文件指针重置到文件起始位置rewind(pf);ret = fgetc(pf);printf("%c\n", ret);//关闭文件fclose(pf);pf = NULL;return 0;
}
运行结果:
结果也如我们所想的那样,从偏移量为6的地方,重置到偏移量为0的起始位置了。
7. 文件读取结束的判定方法
这个判定方法其实就是跟这个函数的返回值有关,每个函数在读取正常时有一个返回值,读取错误时也有一个返回时,那么我们可以根据此函数的返回值来判定是正常结束,还是遇到错误结束。
例如:
fgetc :可以通过返回值是否为 EOF 来判断。
fgets :可以通过返回值是否为 NULL 来判断。
fread :通过它的返回值介绍:
可以判断返回值是否小于实际要读的个数。
7.1 feof函数的具体作用
这个函数不能用来判断文件是否结束,它的功能实际上是判断文件是否是读取到文件末尾才结束的。
同时,它和有一个函数正好可以对比一下,ferror函数,这个函数是判断文件读取是否是遇到错误后而结束的。
实例:
#include <stdio.h>int main()
{//打开文件FILE* pf = fopen("test.txt", "r");if (NULL == pf) {perror("File opening failed");return -1;}//fgetc 当读取失败的时候或者遇到文件结束的时候,都会返回EOFint c = 0; //fgetc函数的返回值为 int。while ((c = fgetc(pf)) != EOF) //循环读取字符,并打印{putchar(c);}//判断是什么原因结束的if (ferror(pf)) //读取到文件末尾结束puts("I/O error when reading");else if (feof(pf)) //读取文件错误结束puts("End of file reached successfully");//关闭文件fclose(pf);pf = NULL;return 0;
}
最后,这里只讲了写操作函数,有关于读操作函数没有详细说明,但是,它们的用法和写操作都是大同小异的,相信只要搞清楚了写操作,再按照在以下网站查找的文档介绍,大家都可以很快的了解清楚。
cplusplus.com - The C++ Resources Network