struct _IO_FILE
struct _IO_FILE {
char* _IO_buf_base; 缓冲区的起始地址
char* _IO_buf_end; 缓冲区结束地址
int _fileno; 文件描述符
...
}
定义:
/* Standard streams. */
extern struct _IO_FILE *stdin; /* Standard input stream. */
extern struct _IO_FILE *stdout; /* Standard output stream. */
extern struct _IO_FILE *stderr; /* Standard error output stream. */
fopen
打开一个文件,并返回流指针
头文件:
#include <stdio.h>
原型:
FILE *fopen(const char *path, const char *mode);
参数:
char *path:文件路径+文件名;
char *mode:打开方式;
r 以只读的方式打开文件。如果文件不存在,则打开失败。
r+ 以读写的方式打开文件。如果文件不存在,则打开失败。
w 以只写的方式打开文件。如果文件不存在,则创建文件;如果文件存在,则清空文件。
w+ 以读写的方式打开文件。如果文件不存在,则创建文件;如果文件存在,则清空文件。
a 以追加写的方式打开文件以进行追加(在文件末尾写入)。如果文件不存在,则创建该文件。流位于文件的末尾。
a+ 以追加读写的方式打开文件以进行读取和追加(在文件末尾写入)。如果文件不存在,则创建该文件。读取时文件指针位置在文件的开头,但是写入时始终附加在文件的结尾。
返回值:
成功,返回流指针;
失败,返回NULL,设置errno;
例程:
//以只读权限打开当前目录的file.txt文件。如果文件不存在,打开失败。
FILE *fp = fopen("./file.txt","r");
//以可读可写权限打开当前目录的file.txt文件。如果文件不存在,打开失败。
FILE *fp = fopen("./file.txt","r+");
//以只写权限打开当前目录的file.txt文件。如果文件存在,打开并清空文件内容;如果文件不存在,则创建文件并打开。
FILE *fp = fopen("./file.txt","w");
//以可读可写权限打开当前目录的file.txt文件。如果文件存在,打开并清空文件内容;如果文件不存在,则创建文件并打开。
FILE *fp = fopen("./file.txt","w+");
//以只写的权限打开当前目录的file.txt文件。
FILE *fp = fopen("./file.txt","a");
//以追加读写的权限打开当前目录的file.txt文件。
FILE *fp = fopen("./file.txt","a+");
if(NULL == fp)
{
printf("%d\n", errno);
perror("fopen");
return -1;
}
fclose
关闭文件(流指针),释放缓冲区
头文件:
#include <stdio.h>
原型:
int fclose(FILE *fp);
参数:
FILE *fp:指定要关闭的缓冲区流指针;
返回值:
成功,返回0;
失败,返回EOF(-1),更新errno
例程:
if(fclose(fp) < 0)
{
perror("fclose");
return -1;
}
printf("关闭成功\n");
fscanf
从文件中格式化获取数据
头文件:
#include <stdio.h>
原型:
int scanf(const char *format, ...);
int fscanf(FILE *stream, const char *format, ...);
参数:
FILE *stream:流指针;
const char *format:标准格式化输入;
...:不定参数;
返回值:
成功,返回获取到的数据个数;
失败或文件读取到结尾,返回EOF,更新errno;
例程:
char s_r[20] = "";
fscanf(fp_r, "%s", s_r);
fprintf
将数据格式化输出到文件中
头文件:
#include <stdio.h>
原型:
int printf(const char *format, ...);
int fprintf(FILE *stream, const char *format, ...);
参数:
FILE *stream:流指针;
const char *format:标准格式化输出;
...:不定参数;
返回值:
成功,输出返回的数据格式,字节为单位;
失败,返回负数,更新errno;
例程:
fprintf(fp, "hello world\n");
fgetc
从文件中获取单个字符
头文件:
#include <stdio.h>
原型:
int fgetc(FILE *stream);
int getchar(void);
参数:
FILE *stream:流指针;
返回值:
成功,返回读取到的文件字符;
失败或文件读取完毕,返回EOF,更新errno;
例子:
char d = 0;
d = fgetc(fp_r);
fputc
将单个字符输出到文件中
头文件:
#include <stdio.h>
原型:
int fputc(int c, FILE *stream);
int putchar(int c);
参数:
int c:指定要输出的字符;
FILE *stream:流指针;
返回值:
成功,返回输出字符的ascii的值;
失败,返回EOF,更新errno;
例程:
fputc('a', fp);
fgets
从文件中获取字符串
头文件:
#include <stdio.h>
原型:
char *fgets(char *s, int size, FILE *stream);
char *gets(char *s);
参数:
char *s:存储获取到的字符串;
int size:一次读取多少个字节;从文件中读取size-1个字符,因为要保留'\0'位置,fgets会自动补上‘\0’。注意:如果一行不足size-1个字符,则读取个数为一行的实际个数;
FILE *stream:指定流指针;
返回值:
成功,返回s的首地址;
失败,返回NULL,更新errno;
例程:
char s[20] = "";
//宏BUFSIZ 8192
if(fgets(s, BUFSIZ, fp_r) == NULL)
{
perror("fgets");
return -1;
}
printf("%s\n", s);
fputs
将字符串输出到文件中
头文件:
#include <stdio.h>
原型:
int fputs(const char *s, FILE *stream);
int puts(const char *s);
参数:
char *s:要输出的字符串首地址;
FILE *stream:指定流指针。流指针为stdout时,相当于puts;
返回值:
成功,返回非负数;
失败,返回EOF,更新errno;
例子:
char s[20] = "hello";
fputs(s, fp);
fputs(s, stdout);
fread
获取文件中的数据,以二进制形式
头文件:
#include <stdio.h>
原型:
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
参数:
void *ptr:存储读取到的数据的数组首地址,可以是任意类型;
size_t size:以size个字节为单位读取,例如:
如果要读取的数据是int类型,size == 4;
如果要读取的数据是char类型,size == 1;
如果要读取的数据是float类型,size == 4;
如果要读取的数据是结构体类型,size == sizeof(结构体);
size_t nmemb:要读取的数据个数;
FILE *stream:流指针;
返回值:
成功,返回读取的数据个数,其实就是 nmemb 的数值;
失败,返回0,或小于nmemb,更新errno;
例程:
int arr[5] = {0};
fread(arr, 4, 3, fp);
fwrite
将数据以二进制的格式输出到文件中
头文件:
#include <stdio.h>
原型:
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
参数:
void *ptr:要输出的数据的数组首地址,可以是任意类型;
size_t size:以size个字节为单位输出,例如:
如果要输出的数据是int类型,size == 4;
如果要输出的数据是char类型,size == 1;
如果要输出的数据是float类型,size == 4;
如果要输出的数据是结构体类型,size == sizeof(结构体);
size_t nmemb:要输出的数据个数;
FILE *stream:流指针;
返回值:
成功,返回输出的数据个数,其实就是 nmemb 的数值;
失败,返回0,或小于nmemb,更新errno;
例程:
int arr[3] = {90, 91, 92};
size_t ret = fwrite(arr, 4, 3, fp_w);
if(ret < 3)
{
perror("fwrite");
return -1;
}
fseek
偏移文件指针
头文件:
#include <stdio.h>
原型:
int fseek(FILE *stream, long offset, int whence);
参数:
FILE *stream:流指针;
long offset:相对于参数whence的偏移量;
int whence:文件指针位置:
SEEK_SET:文件开头位置。
SEEK_CUR:文件当前位置;
SEEK_END:文件结尾位置;
返回值:
成功,返回0;
失败,返回-1;
例程:
//将文件指针偏移到文件开头位置。
fseek(fp, 0, SEEK_SET);
//将文件指针偏移到文件开头后一位。
fseek(fp, 1, SEEK_SET);
rewind
将文件指针偏移到文件开头位置
头文件:
#include <stdio.h>
原型:
void rewind(FILE *stream);
参数:
FILE *stream:流指针;
例程:
rewind(fp); //相当于 fseek(fp, 0, SEEK_SET);
ftell
获取文件指针相对于当前位置到文件开头的偏移量
头文件:
#include <stdio.h>;
原型:
long ftell(FILE *stream);
参数:
FILE *stream:流指针;
返回值:
成功,返回文件指针相对于当前位置到文件开头的偏移量;
失败,返回-1;
例程:
//计算文件大小
fseek(fp, 0, SEEK_END);
printf("len = %ld\n", ftell(fp));
fflush
强制刷新缓冲区
头文件:
#include <stdio.h>
原型:
int fflush(FILE *stream);
参数:
FILE *stream:流指针;
返回值:
成功,返回0;
失败,返回EOF,更新errno;
例程:
fflush(fp);
sscanf
从一个字符串中读取数据
头文件:
#include <stdio.h>
原型:
int sscanf(const char *str, const char *format, ...);
参数:
char *str:要读取的字符串的首地址;
const char *format:标准格式化输入;
...:不定参数;
返回值:
成功,返回读取的字符数;
失败,返回EOF,更新errno;
例程:
int day, year;
char dtm[100], weekday[20], month[20];
strcpy( dtm, "Saturday April 10 2021" );
sscanf( dtm, "%s %s %d %d", weekday, month, &day, &year );
sprintf
输出字符串到一个数组中
头文件:
#include <stdio.h>
原型:
int sprintf(char *str, const char *format, ...);
参数:
char *str:目标字符串的首地址;
const char *format:标准格式化输出;
...:不定参数;
返回值:
成功,返回输出的字符数;
失败,返回负数,更新errno;
例程:
char str[10] = "";
char src[10] = "hello";
sprintf(str,"%s",src);
perror
根据errno打印错误信息
errno:本质上是一个全局变量,对文件进行操作的时候,会出现各种错误,例如文件不存在,文件权限不足的情况,errno中已经定义好了各种数值(详见:/usr/include/asm-generic),与错误对应。
要打印errno的值需要包含 #include <errno.h>
头文件:
#include <stdio.h>
原型:
void perror(const char *s);
参数:
char *s:用于提示的字符串;
例程:
perror("fopen");
应用例程
获取当前的时间,以日历的形式输出到time.txt中。要求如下:
格式:[行号] 时间
[0] 2020-12-21 16-58-06
[1] 2020-12-21 16-58-07
[2] 2020-12-21 16-59-00
[3] 2020-12-21 17-02-00
程序结束后,再次运行程序,保证编号从上次的编号开始
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#define N 30
char *get_everyTime(char *every_time,FILE *fp);
int get_sequence(char *last_time);
char last_time[N] = "";
int main(int argc, const char *argv[])
{
time_t t;
int sequence = 0;
t = time(NULL);//获取当前的总秒数
struct tm* tm = NULL;
tm = localtime(&t);//获取日历对象
if(NULL == tm)
{
perror("localtime");
return -1;
}
FILE *fp = fopen("time.txt","a+");//以读取追加权限打开文件time.txt
if(NULL == fp)
{
perror("fopen");
return -1;
}
char every_time[N] = "";
char last_time[N] = "";
//打印已有的日记数据并返回最后的日历数据
int state = sprintf(last_time,"%s",get_everyTime(every_time,fp));
if(EOF == state)
{
perror("sprintf");
return -1;
}
if(0 == state)//若文件内容为空,则加入第一条日历信息
{
sprintf(last_time,"[%d] %d-%02d-%02d %02d:%02d:%02d\n",sequence,tm->tm_year+1900,\
tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min,\
tm->tm_sec);
fputs(last_time,fp);
printf("%s\n",last_time);
}
if(state > 0)//文件不为空,在文件末尾加入一条日历信息
{
sequence = get_sequence(last_time);
//printf("%d\n",sequence);//test
sprintf(last_time,"[%d] %d-%02d-%02d %02d:%02d:%02d\n",sequence,tm->tm_year+1900,\
tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min,\
tm->tm_sec);
fputs(last_time,fp);
printf("%s\n",last_time);
}
fclose(fp);
return 0;
}
//打印已有的日记数据并返回最后的日历数据
char *get_everyTime(char *every_time,FILE *fp)
{
while(fgets(every_time,N,fp)!=NULL)
{
printf("%s\n",every_time);
}
int sprintf_state = sprintf(last_time,"%s",every_time);
if(EOF == sprintf_state)
{
perror("sprintf_state");
return NULL;
}
return last_time;
}
//获取文件中最后的序号
int get_sequence(char *last_time)
{
int last_sequence=0,i=0;
char num_char[10] = "";
char *p = last_time;
p++;
while(*p!=']')
{
num_char[i] = *p;
i++;
p++;
}
last_sequence = atoi(num_char);
last_sequence += 1;
return last_sequence;
}
//获取行号 方法2:
int get_file_line(FILE* fp)
{
int count = 0;
int c = 0;
while((c=fgetc(fp)) != EOF)
{
if(c == '\n')
count++;
}
return count;
}
结果
本文链接:https://shengto.top/c/stdIO_routine.html
转载时须注明出处及本声明