栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

c语言文件操作--标准IO

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

c语言文件操作--标准IO

目录

一、缓冲文件系统

1、目的

2、定义

3、分类

二、EOF,stdin、stdout、stderr

三、标准IO函数

1、fopen()、fclose()

 2、feof()、ferror()、clearerr()、perror()

3、getc()、getchar()、fgetc()

4、putc()、fputc()、putchar()

5、puts()、fputs()

 6、gets()、fgets()

7、fread()、fwrite()

 8、fprintf()、 fscanf()

9、fseek()、ftell()、rewind()


一、缓冲文件系统

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 

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、feof()、ferror()、clearerr()、perror()

a、函数定义

#include 

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

 b、注意事项

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

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

a、函数定义

#include 

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 

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 

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

b、注意事项

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

3.6、gets()、fgets()

a、函数定义

 #include 

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

b、注意事项

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

3.7、fread()、fwrite()

a、函数定义

#include 

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 

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 

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

    
//    fputc(fgetc(src_fd),dest_fd);
//    while (!feof(src_fd)){
//        fputc(fgetc(src_fd),dest_fd);
//    }

    
//    char buf[1024];
//    while( fgets(buf, sizeof(buf),src_fd) != NULL){
//        fputs(buf,dest_fd);
//    }

    
    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("%ldn",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:%02dn"
                ,num,year, mon,day,hour,min,sec);
        fflush(fd);//强制刷出缓存

        //在控制台实时打印
        fprintf(stdout,"%04d, %02d-%02d-%02d %02d:%02d:%02dn"
                ,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 
#include 
#include 

//文本文件拷贝
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("%ldn", 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;
    }

    
//    fputc(fgetc(src_fd),dest_fd);
//    while (!feof(src_fd)){
//        fputc(fgetc(src_fd),dest_fd);
//    }

    
//    char buf[1024];
//    while( fgets(buf, sizeof(buf),src_fd) != NULL){
//        fputs(buf,dest_fd);
//    }

    
    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("%ldn",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:%02dn"
                ,num,year, mon,day,hour,min,sec);
        fflush(fd);//强制刷出缓存

        fprintf(stdout,"%04d, %02d-%02d-%02d %02d:%02d:%02dn"
                ,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;
}

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/867822.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号