目录
前言
上文对标准IO、流及缓冲区的概念进行介绍并进行了相关实验,上文链接点这里,本文来介绍使用标准IO进行文件的打开、关闭、读、写等相关操作。
文件的打开和关闭的概念
打开就是占用资源
关闭就是释放资源
文件的打开
文件的打开函数
FILE *fopen (const char *path, const char *mode);
path:普通文件当前路径不需要加目录,其他要使用完成的路径
mode:文件打开的模式
返回值:出错返回NULL,所以使用fopen函数必须判断是否为空
文件打开的模式
"r"或"rb" | 以只读方式打开文件,文件必须存在。 |
"r+"或"r+b" | 以读写方式打开文件,文件必须存在 |
"w"或"wb" | 以只写方式打开文件,若文件存在则文件长度清为0。若文件不存在则创建。 |
"w+"或"w+b" | 以读写方式打开文件,其他同"w"。 |
"a"或"ab" | 以只写方式打开文件,若文件不存在则创建;向文件写入的数据被追加到文件末尾。 |
"a+"或"a+b" | 以读写方式打开文件。其他同"a"。 |
文件的关闭
文件的关闭函数
int fclose(FILE *stream)
fclose()调用成功返回0,失败返回EOF(-1),并设置errno。
流关闭时自动刷新缓冲中的数据并释放缓冲区,比如:常规文件把缓冲区内容写入磁盘。
当一个程序正常终止时,所有打开的流都会被关闭。
注意事项
fclose()函数的入参stream必须保证为非空,否则出现断错误。
字符的输入(读单个字符)
字符输入的函数
int fgetc(FILE *stream);
int getc(FILE *stream); //宏
int getchar(void);
成功时返回读取的字符,若到文件末尾或出错时返回EOF(-1)。
getchar()等同于fgetc(stdin)
getc和fgetc区别就是一个时宏一个是函数
注意事项
1、函数返回值是int类型不是char类型,主要是为了扩展返回值的范围。
2、stdin也是FILE*的指针,是系统定义好的,指向的是标准输入(键盘输入)。
3、打开文件后读取,是从文件开头开始读,读完一个后读写指针会后移。
4、调用getchar会阻塞,等待你的键盘输入
字符的输出(写单个字符)
字符输出的函数
int fputc(int c, FILE *stream);
int putc(int c, FILE *stream);
int putchar(int c);
成功时返回写入的字符;出错时返回EOF。
putchar(c)等同于fputc(c, stdout)。
注意事项
1、返回和输入参数都是int类型
2、遇到这种错误:Bad file descriptor, 很可能是文件打开的模式错误(只读模式去写,只写模式去读)
行输入(读取整个行)
行输入的函数
char *gets(char *s); 读取标准输入到缓冲区s
char *fgets(char *s, int size, FILE *stream);
成功时返回s,到文件末尾或出错时返回NULL
遇到’\n’或已输入size-1个字符时返回,总是包含’\0’
注意事项
1、gets函数已经被淘汰,因为会导致缓冲区溢出
2、fgets 函数第二个参数,输入的数据超出size,size-1个字符会保存到缓冲区,最后添加’\0’,如果输入数据少于size-1 后面会添加换行符。
行输出(写整行)
行输出的函数
int puts(const char *s);
int fputs(const char *s, FILE *stream);
成功时返回非负整数;出错时返回EOF
puts将缓冲区s中的字符串输出到stdout,并追加’\n’
fputs将缓冲区s中的字符串输出到stream,不追加 ‘\n’
二进制读写
文本文件和二进制的区别
存储的格式不同:文本文件只能存储文本。
计算机内码概念:文本符号在计算机内部的编码(计算机内部只能存储数字0101001....,所以所有符号都要编码)
二进制读写函数
size_t fread(void *ptr, size_t size, size_t n, FILE *fp);
//void *ptr 读取内容放的位置指针
//size_t size 读取的块大小
//size_t n 读取的个数
//FILE *fp 读取的文件指针
size_t fwrite(const void *ptr, size_t size, size_t n, FILE *fp);
//void *ptr 写文件的内容的位置指针
//size_t size 写的块大小
//size_t n 写的个数
//FILE *fp 要写的文件指针
注意事项
文件写完后,文件指针指向文件末尾,如果这时候读,读不出来内容。
解决办法:移动指针(后面讲解)到文件头;关闭文件,重新打开
流的刷新
流的刷新函数
int fflush(FILE *fp);
成功时返回0;出错时返回EOF。
将流缓冲区中的数据写入实际的文件。
Linux下只能刷新输出缓冲区,输入缓冲区丢弃。
如果输出到屏幕使用fflush(stdout)。
流的定位
流的定位函数
long ftell(FILE *stream);
long fseek(FILE *stream, long offset, int whence);
void rewind(FILE *stream);
ftell()成功时返回当前读写位置,出错时返回EOF。
fseek()定位一个流,成功时返回0,出错时返回EOF。
rewind()将流定位到文件开始位置
whence参数:SEEK_SET/SEEK_CUR/SEEK_END
offset参数:偏移量,可正可负
SEEK_SET | 从距文件开头 offset 位移量为新的读写位置 |
SEEK_CUR | 以目前的读写位置往后增加 offset 个位移量 |
SEEK_END | 将读写位置指向文件尾后再增加 offset 个位移量 |
注意事项
1、打开a模式,fseek无效
2、读写流时,当前读写位置自动后移。
判断流是否出错和结束
判断流是否出错和结束函数
#include <stdio.h>
int ferror(FILE *stream);
int feof(FILE *stream);
ferror()返回1表示流出错;否则返回
feof()返回1表示文件已到末尾;否则返回0
格式化输出
格式化输出函数
int fprintf(FILE *stream, const char *fmt, …);
int sprintf(char *s, const char *fmt, …);
成功时返回输出的字符个数;出错时返回EOF。
格式化输入
格式化输入函数
int fscanf(FILE *stream, const char *format, ...);
int sscanf(const char *str, const char *format, ...);
代码练习
要求
1、每隔1s以指定格式 “年-月-日” 分别写入文件和缓冲区;
2、该程序无限循环,直到Ctrl+C中断程序;
具体实现代码
#include <stdio.h>
#include <time.h>
#include <unistd.h>
#include <string.h>
int main(int argc,const char* argv)
{
FILE *fp;
time_t ctime;
struct tm *ctimester;
int linecount = 0;
char buf[32];
fp = fopen("1.txt","a+");
if(fp == NULL)
{
perror("fopen");
return 0;
}
//calculate 1.txt line
while(fgets(buf,32,fp)!=NULL)
{
if(buf[strlen(buf)-1] == '\n')
{
linecount++;
}
}
while(1)
{
ctime = time(NULL);
ctimester = localtime(&ctime);
printf("%04d-%02d-%02d %02d:%02d:%02d\n",ctimester->tm_year+1900,
ctimester->tm_mon+1,
ctimester->tm_mday,
ctimester->tm_hour,
ctimester->tm_min,
ctimester->tm_sec);
fprintf(fp,"%d, %04d-%02d-%02d %02d:%02d:%02d\n",linecount++,ctimester->tm_year+1900,
ctimester->tm_mon+1,
ctimester->tm_mday,
ctimester->tm_hour,
ctimester->tm_min,
ctimester->tm_sec);
fflush(fp);
sleep(1);
}
fclose(fp);
return 0;
}
测试结果
总结
本文总结了C语言标准IO的输入、输出、读写、流的刷新定位等相关概念及函数介绍,并根据这些函数进行了一个包含文件打开关闭、读写、格式化输出等内容的实现。