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;
} 

结果

Last modification:2021 年 04 月 10 日 15 : 48 : 36