C语言文件读写操作
参考《C Primer Plus 第六版(中文版)》
文章目录- 读文件
- 写文件
- 其他读写函数
- 注意
- 标准IO的流程
- 关于缓冲区的一个例子
- 读文件
#include "stdio.h"
#define TEST_FILE_PATH "TestFile.txt"//测试文件路径
int main(void)
{
int character;//用于存储读取到的单个字符
FILE* file_pointer;//文件指针,其中FILE是一个结构体,于是file_pointer是一个结构体指针
//fopen()函数打开文件,将函数返回的文件信息结构体指针赋值给结构体指针变量file_pointer
file_pointer = fopen(TEST_FILE_PATH,"r");
//进入逐字符读取循环前首先判定文件是否为空文件(getc()函数将逐字符读取数据,读到文件末尾时将返回EOF,EOF值为-1)
while((character = getc(file_pointer)) != EOF)
{
printf("%c",character);//将读到的字符连续打印出来
}
fclose(file_pointer);//关闭指定文件
printf("nOutput end!n");//输出完毕
return 0;
}
- 关于FILE
以下是FILE结构体的定义
typedef struct _iobuf
{
char *_ptr;
int _cnt;
char *_base;
int _flag;
int _file;
int _charbuf;
int _bufsiz;
char *_tmpfname;
} FILE;
不大清除这些数据都是啥,但是可以知道的是,它是一个“文件信息的填写模板”,在上面读文件的代码中,file_pointer就是一个指向这种结构体的指针,fopen()函数打开文件后返回“一张单子”(FILE类型结构体指针),这张单子包含我们操作的这个文件的缓冲区信息(个人理解是:fopen()函数读取文件需要将文件数据读取到缓冲区,然后返回文件数据在缓冲区的位置信息返回出去)。
根据文件数据的位置信息,我们可以读取到文件数据。
- 关于fopen()
getc()和putc()函数与getchar()和putchar()函数类似。所不同的是,要告诉
getc()和putc()函数使用哪一个文件。下面这条语句的意思是“从标准输入中
获取一个字符”:
ch = getchar();
然而,下面这条语句的意思是“从fp指定的文件中获取一个字符”:
ch = getc(fp);与此类似,下面语句的意思是“把字符ch放入FILE指针fpout指定的文件
中”:——《C Primer Plus 第六版(中文版)》
fopen()打开文件需要指定打开的模式:
写文件利用putc()写文件貌似和读文件差不多;
void FileWriteTest()
{
int i = 0;
FILE* file_pointer;
char TestString[] = "This is the test string;
nIf you see this sentence in the test txt file, the file is written successfully.";
file_pointer = fopen(TEST_FILE_PATH,"w");//打开文件
//开始写入数据
while(TestString[i]!=' ')
{
putc(TestString[i],file_pointer);
i++;
}
fclose(file_pointer);//写入结束,关闭指定文件
printf("nEnd of file writing!n");
}
其他读写函数
//fprintf()
int fprintf (FILE *__stream, const char *__format, ...);
//fscanf()
int fscanf (FILE *, const char *, ...);
//fgets()
char * fgets (char *, int, FILE *);
//fputs()
int fputs (const char *, FILE *);
//fseek()
int fseek(FILE *stream, long int offset, int whence);
//ftell()
long int ftell(FILE *stream);
//......
注意
① 文件读写有字符模式和二进制模式;有一些区别,比如是否把Ctrl^Z和rn当作字符的区别;这会导致ftell()等函数的工作不一样。
② 如果ftell(),fseek()函数的long int不够用,还有fgetpos()和fsetpos()函数也可以实现功能;
标准IO的流程-
首先,使用fopen()打开文件;并且创建缓冲区,创建文件信息结构体,返回指向该结构体的指针。关于缓冲区
-
使用getc()等函数去读取字符时,文件数据(的一部分,如512byte或1Kb等等,取决于缓冲区大小和缓冲区模式等)被复制到缓冲区。
-
当缓冲区中的数据读完之后,新的一部分文件数据被复制到缓冲区。
-
以这种方式,输入函数可以读取文件中的所有内容,直到文件结尾。函数在读取缓冲区中的最后一个字符后,把
结尾指示器设置为真。于是,下一次被调用的输入函数将返回EOF。
- 代码来自菜鸟教程
#include#include #include int main() { char buff[1024];//定义一个字符型数组作为缓冲区 memset( buff, ' ', sizeof( buff ));//初始化缓冲区 fprintf(stdout, "启用全缓冲n");//将这句话输出到默认stdout缓冲区 setvbuf(stdout, buff, _IOFBF, 1024);//定义stdout流,缓冲区设置为从buff开始,全缓冲,缓冲区大小1Kb fprintf(stdout, "这里是 runoob.comn");//将这两句话输出到现在的stdout缓冲区 fprintf(stdout, "该输出将保存到 buffn"); fflush( stdout );//刷新缓冲区,缓冲区中字符这时候才被输出到显示器(stdout) fprintf(stdout, "这将在编程时出现n");//这两句话也被输出stdout缓冲区 fprintf(stdout, "最后休眠五秒钟n");//但是后面没有了刷新缓冲区的操作,并且缓冲区也没被填满 //所以这两句话并不会输出到显示器上 sleep(5); return(0); }
- Debug过程;(多图预警)
此时还没有执行memset( buff, ' ', sizeof( buff )),可以看到数组内部是垃圾数据。
初始化之后;
输出到默认缓冲区,显示器上没有输出,因为既没有刷新默认缓冲区,缓冲区也没被填满。
重新设置了stdout缓冲区之后,原来默认的缓冲区里的数据(“启用全缓冲”)被输出;
数据被输出到现在的缓冲区(buff);
刷新缓冲区之后,缓冲区数据被输出;
但是,缓冲区中的数据并没有被删除!!(终端显示的[New Thread xxx]请无视,偶然出现)
新的数据被写入时将原来的数据覆盖,还没被覆盖的数据依然还在!!
所以,可以知道fflush()函数并不会刷新缓冲区并不会删除缓冲区中的内容,只是像在一行字上再写一行字一样,只把笔尖重新定位到行首,而不划掉已经写了的字。
to be continued…



