linux -- 标准IO

目录

一、缓冲文件系统

1.1、目的

1.2、定义

1.3、分类

二、EOF,stdin、stdout、stderr

三、标准IO函数

3.1、fopen()、fclose()

3.2、fileno()、feof()、ferror()、clearerr()、perror()

3.3、getc()、getchar()、fgetc()

3.4、putc()、fputc()、putchar()

3.5、puts()、fputs()

3.6、gets()、fgets()

3.7、fread()、fwrite()

3.8、fprintf()、 fscanf()

3.9、fseek()、ftell()、rewind()

四、一些简单实践

4.1、文本文件的拷贝

4.2、打印日志文件

 4.3、查看文件的大小

4.4、完整测试代码


一、缓冲文件系统

1.1、目的

▪ 尽量减少使用read/write的调用

1.2、定义

▪ 系统自动的在内存中为每一个正在使用的文件开辟一个缓冲区, 从内存向磁盘输出数据必须先送到内存缓冲区,装满缓冲区在一起送 到磁盘中去。

▪ 从磁盘中读数据,则一次从磁盘文件将一批数据读入到 内存缓冲区中,然后再从缓冲区逐个的将数据送到程序的数据区。

1.3、分类

a、全缓存

▪ 当填满I/O缓存后才进行实际I/O操作,或者满足一定条件后,系统通过调用malloc来获得所需要的缓冲区域

▪ 当缓冲区满了,或者满足一定的条件后,就会执行刷新操作。

b、行缓存

▪ 当在输入和输出中遇到新行符(‘\n’)时,进行I/O操作

c、不缓存

▪ 标准I/O库不对字符进行缓冲,例如stderr。

▪ 很多的人机交互界面要求不可全缓存。

▪  标准出错决不会是全缓存的。 

d、在任何时刻,可以使用fflush强制刷出缓存区

二、EOF,stdin、stdout、stderr


extern FILE *stdin; 标准输入
extern FILE *stdout; 标准输出
extern FILE *stderr; 标准错误

//EOF end of file 文件结束符

三、标准IO函数

3.1、fopen()、fclose()

a、函数定义

#include <stdio.h>

FILE *fopen(const char *pathname, const char *mode);
int fclose(FILE *stream);

b、参数含义

pathname:路径
        绝对路径:"D:/test01/a.txt"
        相对路径 "./a.txt"
mode:访问方式
        w write 只写 文件不存在则创建,文件存在则清空
        r read 只读 不能创建
        a apped 以追加的方式写 文件不存在则创建
        b binary 以二进制的方式操作 wb rb ab
        + 可读可写 w+ r+ a+

c、 注意事项

  • fopen():成功返回文件指针,失败返回NULL
  • fclose():成功返回0,失败返回EOF
  • 在该文件被关闭之前,刷新缓存中的数据。
  • 当一个进程正常终止时,则所有带未写缓存数据的标准I / O流都被刷新,所有打开的标准I / O流都被关闭。
  • 在调用fclose()关闭流后对流所进行的任何操作,包括再次调用fclose(),其 结果都将是未知的

3.2、fileno()、feof()、ferror()、clearerr()、perror()

a、函数定义

#include <stdio.h>

int fileno(FILE *stream);
void clearerr(FILE *stream);
int feof(FILE *stream);
int ferror(FILE *stream);
void perror(const char *s);

 b、注意事项

  • fileno()、把标准文件描述符转为文件IO描述符 返回文件IO描述符
  • feof()检测文件结束符,如果文件结束,返回非0值,否则返回0(一般先读取再判断)
  • ferror()检测错误标识符,如果有返回非0值,否则返回0 (如:读取只写;返回非0值)
  • clearerr()清除文件结束符和错误标识符 且这两个只能由其清除
  • perror()在错误信息打印之前,输出自定义信息

3.3、getc()、getchar()、fgetc()

a、函数定义

#include <stdio.h>

int fgetc(FILE *stream);
int getc(FILE *stream);
int getchar(void);

b、 注意事项

  • 三个函数都是从流中获取一个字符、返回值为int型
  • 成功返回获取的字符,若已处于文件尾端或出错则返回EOF,要区分这两种不同的情况,必须调用ferror()或feof()。
  • getc()等价于fgetc(),只是getc()的实现是一个宏,而fgetc()是一个函数。
  • 函数getchar()等同于getc(stdin)

3.4、putc()、fputc()、putchar()

a、函数定义

#include <stdio.h>

int fputc(int c, FILE *stream);
int putc(int c, FILE *stream);
int putchar(int c);

b 、注意事项

  • 成功返回写入的字符,失败返回EOF
  • putc()等价于fputc(),只是putc()的实现是一个宏,而fputc()是一个函数。
  • putchar('c')等价于putc('c',stdout)。

3.5、puts()、fputs()

a、函数定义

#include <stdio.h>

int puts(const char *s);
int fputs(const char *s, FILE *stream);

b、注意事项

  • 成功返回非负数(不是写入的字符数),失败返回EOF
  • 两个都是遇到  \0 就停止写入,不会将 \0 写入 , 遇到 \n 不会停止写入
  • fputs不会主动添加\n符号到目标流内()
  • puts会主动添加\n符号到标准输出

3.6、gets()、fgets()

a、函数定义

 #include <stdio.h>

char *fgets(char *s, int size, FILE *stream);
char *gets(char *s);

b、注意事项

  • 成功返回缓存的首地址(即 s),若已处文件尾端或出错则为null
  • fgets最多读取size-1个字符 并在后面加上 \0 ,当遇到 \n 会结束读取,并将 \n 写入
  • 不推荐使用 gets(),因为gets()不能指定缓存的长度,这样就可能造成缓存越界;

3.7、fread()、fwrite()

a、函数定义

#include <stdio.h>

size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
size_t fwrite(const void *ptr, size_t size, size_t nmemb,FILE *stream);

b、参数含义

  • ptr:要读/写内容的首地址
  • size:一般为ptr所指向类型的大小 

                假如: char a[10];  char *ptr = a; 则size = sizeof(char)

                size和nmemb不固定,只要 size*nmemb = sizeof(a) 就行

  • nmemb:要读/写的条目数
  • stream:要读/写的文件

c、注意事项

  • 成功返回读/写入的 nmemb 的值(不一定为nmemb),错误或到达文件末尾返回0
  • 可以以二进制的方式读/写

3.8、fprintf()、 fscanf()

a、函数定义

#include <stdio.h>

int fprintf(FILE *stream, const char *format, ...);
int fscanf(FILE *stream, const char *format, ...);

b、注意

  • 成功返回写入的字节数,失败返回 EOF
  • prinf() == fprintf(stdout,)
  • scanf() == fscanf(stdin,)

3.9、fseek()、ftell()、rewind()

a、函数定义

#include <stdio.h>

int fseek(FILE *stream, long offset, int whence);
long ftell(FILE *stream);
void rewind(FILE *stream);
int fgetpos(FILE *stream, fpos_t *pos);
int fsetpos(FILE *stream, const fpos_t *pos);
  • fseek

用于重置stream流的位置,调用成功返回0,失败返回 -1

offset:偏移量,每一读写操作所需要移动的距离,单位是字节的 ,可正可负(向前移,向后移)

whence
SEEK_SET:当前位置为文件的开头,新位置为偏移量 的大小。
SEEK_CUR:当前位置为文件指针的位置,新位置为 当前位置加上偏移量。
SEEK_END:当前位置为文件的结尾,新位置为文件的大小加上偏移量的大小。

  • ftell

 用于获取当前文件位置,调用成功返回当前偏移量。失败返回  -1

  • rewind

将stream 流设置在文件开头 无返回值

 相当于  fseek(stream, 0L, SEEK_SET)

四、一些简单实践

4.1、文本文件的拷贝

int FileCopy(const char *src_path,const char*dest_path){
    //获取源文件的文件指针
    FILE *src_fd = fopen(src_path,"r");
    if(src_fd == NULL){
        perror("open src ");
        return -1;
    }
    //获取目标文件的文件指针
    FILE *dest_fd = fopen(dest_path,"w");
    if(dest_fd == NULL){
        perror("open dest ");
        return -1;
    }

    /*利用标准IO的字符IO,实现2个文件拷贝*/
//    fputc(fgetc(src_fd),dest_fd);
//    while (!feof(src_fd)){
//        fputc(fgetc(src_fd),dest_fd);
//    }

    /*利用标准IO的行IO,实现2个文件拷贝*/
//    char buf[1024];
//    while( fgets(buf, sizeof(buf),src_fd) != NULL){
//        fputs(buf,dest_fd);
//    }

    /*利用标准IO的块IO,实现2个文件拷贝*/
    char buf[1024];
    unsigned long ret = 0;
    ret = fread(buf, 1,sizeof(buf),src_fd);
    while( ret != 0){
        fwrite(buf, 1,ret,dest_fd); //读到多少就写入多少
        printf("%ld\n",ret);
        ret = fread(buf, 1,sizeof(buf),src_fd);
    }

    fclose(src_fd);
    fclose(dest_fd);
    return 0;
}

4.2、打印日志文件

编程读写一个文件 test.txt,每隔 1 秒向文件中写入一行数据,类似这样

0001, 2022-05-08 15:16:42

0002, 2022-05-08 15:16:43

该程序应该无限循环,直到中断程序。下次再启动程序写文件时可以追加到原 文件之后,并且序号能够接续上次的序号,比如:

0001,2022-05-08 15:16:42

0002, 2022-05-08 15:16:43

0003, 2022-05-08 15:19:02

0004, 2022-05-08 15:19:03

0005, 2022-05-0815:19:04

void PrintLogData(const char *path){
    //追加的方式获取文件描述符
    FILE *fd = fopen(path,"a+");
    if(fd == NULL){
        perror("open ");
        return;
    }

    //获取行号
    int num = 0;
    char buf[1024];
    while(fgets(buf, sizeof(buf),fd) !=NULL){
        num++;
    }
    //重置一下fd
    fseek(fd,0,SEEK_CUR);

    //往日志文件写数据
    int year,mon,day,hour,min,sec;
    while(num >= 0){

        //获取当前时间
        time_t now;
        struct tm *tm_now;
        time(&now);
        tm_now = localtime(&now);

        year = tm_now->tm_year+1900;
        mon = tm_now->tm_mon+1;
        day = tm_now->tm_mday;
        hour = tm_now->tm_hour;
        min = tm_now->tm_min;
        sec = tm_now->tm_sec;

        //%04 表示占4位,不足4位 在前面补0
        fprintf(fd,"%04d, %02d-%02d-%02d %02d:%02d:%02d\n"
                ,num,year, mon,day,hour,min,sec);
        fflush(fd);//强制刷出缓存

        //在控制台实时打印
        fprintf(stdout,"%04d, %02d-%02d-%02d %02d:%02d:%02d\n"
                ,num,year, mon,day,hour,min,sec);
        sleep(1);
        num++;
    }

    fclose(fd);
}

 4.3、查看文件的大小

long SizeOfFile(const char *path){
    long size = 0L;
    
    FILE *fd = fopen(path,"r");
    fseek(fd,0,SEEK_END);//偏移到文件末尾
    size = ftell(fd);
    fclose(fd);
    
    return size;
}

4.4、完整测试代码

#include <stdio.h>
#include <time.h>
#include <unistd.h>

//文本文件拷贝
int FileCopy(const char *src_path,const char*dest_path);
//输出日志文件
void PrintLogData(const char *path);
//获取文件大小
long SizeOfFile(const char *path);

int main() {
    char* src_path="./src.txt";
    char* dest_path="./dest.txt";
    char* log_path = "log.txt";
//    PrintLogData(log_path);
//    FileCopy(src_path,dest_path);
//    printf("%ld\n", SizeOfFile(src_path));
    return 0;
}

int FileCopy(const char *src_path,const char*dest_path){
    //获取源文件的文件指针
    FILE *src_fd = fopen(src_path,"r");
    if(src_fd == NULL){
        perror("open src ");
        return -1;
    }
    //获取目标文件的文件指针
    FILE *dest_fd = fopen(dest_path,"w");
    if(dest_fd == NULL){
        perror("open dest ");
        return -1;
    }

    /*利用标准IO的字符IO,实现2个文件的字节拷贝*/
//    fputc(fgetc(src_fd),dest_fd);
//    while (!feof(src_fd)){
//        fputc(fgetc(src_fd),dest_fd);
//    }

    /*利用标准IO的行IO,实现2个文件的字节拷贝*/
//    char buf[1024];
//    while( fgets(buf, sizeof(buf),src_fd) != NULL){
//        fputs(buf,dest_fd);
//    }

    /*利用标准IO的块IO,实现2个文件的字节拷贝*/
    char buf[1024];
    unsigned long ret = 0;
    ret = fread(buf, 1,sizeof(buf),src_fd);
    while( ret != 0){
        fwrite(buf, 1,ret,dest_fd); //读到多少就写入多少
        printf("%ld\n",ret);
        ret = fread(buf, 1,sizeof(buf),src_fd);
    }

    fclose(src_fd);
    fclose(dest_fd);
    return 0;
}

void PrintLogData(const char *path){
    //追加的方式获取文件描述符
    FILE *fd = fopen(path,"a+");
    if(fd == NULL){
        perror("open ");
        return;
    }

    //获取行号
    int num = 0;
    char buf[1024];
    while(fgets(buf, sizeof(buf),fd) !=NULL){
        num++;
    }
    fseek(fd,0,SEEK_CUR);

    //往日志文件写数据
    int year,mon,day,hour,min,sec;
    while(num >= 0){

        //获取当前时间
        time_t now;
        struct tm *tm_now;
        time(&now);
        tm_now = localtime(&now);

        year = tm_now->tm_year+1900;
        mon = tm_now->tm_mon+1;
        day = tm_now->tm_mday;
        hour = tm_now->tm_hour;
        min = tm_now->tm_min;
        sec = tm_now->tm_sec;

        //%04 表示占4位,不足4位 在前面补0
        fprintf(fd,"%04d, %02d-%02d-%02d %02d:%02d:%02d\n"
                ,num,year, mon,day,hour,min,sec);
        fflush(fd);//强制刷出缓存

        fprintf(stdout,"%04d, %02d-%02d-%02d %02d:%02d:%02d\n"
                ,num,year, mon,day,hour,min,sec);
        sleep(1);
        num++;
    }

    fclose(fd);
}

long SizeOfFile(const char *path){
    long size = 0L;

    FILE *fd = fopen(path,"r");
    fseek(fd,0,SEEK_END);//偏移到文件末尾
    size = ftell(fd);
    fclose(fd);

    return size;
}

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值