当前位置: 首页 > news >正文

【Linux文件IO】Linux中标准IO的API的描述和基本用法

Linux中标准IO的API的描述和基本用法

  • 一、标准IO相关API
    • 1、文件的打开和关闭
      • 示例代码:
    • 2、文件的读写
      • 示例代码:
      • 用标准IO(fread、fwrite)实现文件拷贝(任何文件均可拷贝)
    • 3、文件偏移设置
      • 示例代码:
    • 4、fgets fputs fgetc fputc gets puts putchar getchar putc getc
      • 示例代码:
        • (1) fgets按行读取数据
        • (2) fputs写入数据到文件
        • (3) fgets和fputs另外一个功能(标准输入和标准输出)
        • (4) fgetc读取一个字符和fputc写入一个字符
    • 5、判断是否到达文件末尾
      • 示例代码:
    • 6、fprintf和fscanf()
      • 示例代码:
    • 7、主动刷新缓冲区
      • 示例代码:
  • 二、对比系统IO和标准IO的区别
    • 1、
    • 2、
    • 3、

一、标准IO相关API

1、文件的打开和关闭

在这里插入图片描述
注意:

  • 总共有6中打开模式,不能自创别的模式,比如 “rw” 是非法的。
    在这里插入图片描述
    注意:
  • fclose函数涉及内存释放,不可对同一个文件多次关闭

示例代码:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>

int main(int argc, char const *argv[])
{
    FILE * fp;
    // 以只读方式打开文件,要求文件必须存在
    // fp = fopen("1.txt", "r"); //  文件打开失败 提示: No such file or directory
    // 以读写方式打开文件,要求文件必须存在
    // fp = fopen("1.txt", "r+"); //  文件打开失败 提示: No such file or directory
    // 以只写方式打开文件,不存在就新建,存在则清空
    fp = fopen("1.txt", "w"); // 
    if (fp == NULL)
    {
        perror("文件打开失败\n");
        return -1;
    }
    // 关闭文件
    fclose(fp);
    return 0;
}

2、文件的读写

//按照数据块来读取数据
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
       返回值(重点):成功 返回读取到的完整的数据块的个数
                             失败  -1
                   参数:ptr --》存放读取的内容
                         size(重点) --》要读取的数据块大小,字节
                         nmemb(重点) --》打算读取多少个数据块
                         stream --》要读取的那个文件
       比如:read(fd,buf,100);  
             fread(buf,50,2)//读取2个数据块,每个数据块50个字节
             fread(buf,20,5)//读取5个数据块,每个数据块20个字节
             fread(buf,10,10)//读取10个数据块,每个数据块10个字节
             fread(buf,1,100)//读取100个数据块,每个数据块1个字节 
              
       情况1:如果文件剩余的字节数>=100个字节,以上四种写法都可以成功读取100个字节
              区别就是返回值不同
       情况2:如果文件剩余的字节数<100个字节,以上四种写法都可以成功读取剩余所有的字节
              区别就是返回值不同
                
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
      返回值(重点): 成功      nmemb是多少,返回值就是多少
              参数:ptr --》存放要写入的内容
                    size(重点) --》要写入的数据块大小,字节
                    nmemb(重点) --》打算写入多少个数据块
                    stream --》要写入的那个文件
              总结:无论write还是fwrite写入的字节数搞多了,都会找垃圾凑够需要写的字节数
      fwrite第三个参数写的是多少,返回值就是多少

示例代码:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>

/*
    fread返回值:返回完整数据块个数
    fwrite返回值:nmemb是多少,返回值就是多少
*/

int main(int argc, char const *argv[])
{
    FILE *fp = fopen("1.txt", "r+");
    int ret = 0;  
    if (fp == NULL)
    {
        perror("打开文件失败\n");
        return -1;
    }

    char buf[20] = "helloword";
    // ret = fread(buf, 10, 1, fp); // 读取1个数据块,数据块大小为10个字节  读取的内容是:1234567890
    // fread(buf, 5, 2, fp); // 读取2个数据块,数据块大小为5个字节 读取的内容是:1234567890
    // ret = fread(buf, 1, 10, fp); // 读取10个数据块,数据块大小为1个字节  读取的内容是:1234567890
    // fread(buf, 2, 5, fp); // 读取5个数据块,数据块大小为2个字节 读取的内容是:1234567890
    // ret = fread(buf, 6, 2, fp);
    // printf("读取的内容是:%s\n", buf);
    // printf("fread的返回值ret:%d\n", ret);

    ret = fwrite(buf, 10, 1, fp);
    printf("fwrite的返回值ret:%d\n", ret);
    
    return 0;
}

用标准IO(fread、fwrite)实现文件拷贝(任何文件均可拷贝)

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>

int main(int argc, char const *argv[])
{
    char buf[100] = {0};
    int ret = 0;
    FILE *fp1 = fopen("1.txt", "r+");
    if (fp1 == NULL)
    {
        perror("打开文件失败\n");
        return -1;
    }

    FILE *fp2 = fopen("new.txt", "w+");
    if (fp1 == NULL)
    {
        perror("新建文件失败\n");
        return -1;
    }
    while (1)
    {
        bzero(buf, 100);
        // 每次读取100字节,即读取100个数据块,每个数据块1字节
        ret = fread(buf, 1, 100, fp1); 
        // 读取完成则退出循环
        if (ret == 0) 
        {
            break;
        }
        // 写入到目标文件
        fwrite(buf, 1, ret, fp2);
    }
    fclose(fp1);
    fclose(fp2);
    
    return 0;
}

3、文件偏移设置

在这里插入图片描述

示例代码:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>

int main(int argc, char const *argv[])
{
    char buf[100] = {0};
    int ret = 0;
    FILE *fp1 = fopen("1.txt", "r+");
    if (fp1 == NULL)
    {
        perror("打开文件失败\n");
        return -1;
    }

    // 从起始位置往后偏移5个字节,返回值与lseek不一样,0:成功, -1:失败
    ret = fseek(fp1, 5, SEEK_SET);
    printf("fseek的返回值是:%d\n", ret); // fseek的返回值是:0

    // 获取当前光标距离起始位置的字节数
    printf("当前光标距离起始位置的字节数:%ld\n", ftell(fp1)); // 当前光标距离起始位置的字节数:5

    // 读取文件,从第六个字节开始读取
    fread(buf, 1, 5, fp1);
    // 偏移后读取的数据是:world 若读取数据有误,现在linux中手动删除(rm 1.txt)在新建(vim 1.txt)
    printf("偏移后读取的数据是:%s\n", buf); 
    
    // 关闭文件
    fclose(fp1);

    return 0;
}

4、fgets fputs fgetc fputc gets puts putchar getchar putc getc

char *fgets(char *s, int size, FILE *stream);  //按行读取数据,一次最多读取一行(遇到回车结束读取)
       返回值:成功  返回读取的一行数据的首地址
                     失败  NULL
         参数:s  --》存放读取到的一行数据
               size --》打算读取多少字节的数据
               stream --》要从哪个文件读取一行
         特点:假如一行只有10个字符
                   fgets(buf,5,myfile); //只能读取4个有效字符,最后一个fgets会帮你填充\0
                   fgets(buf,11,myfile); //前面10个是有效字符,第11个是\0
                   fgets(buf,12,myfile); //前面11个是有效字符(会把回车\n读取,windows上的回车是\r\n),第12个是\0
int fputs(const char *s, FILE *stream);  //往一个文件中写入字符串
      返回值:成功  >0   失败  -1  
        参数:s --》要写入的内容
              stream --》要写入的那个文件  
      fputs有局限性(char *),只能写入字符串,但是fwrite可以写任意类型(void *)的数据

int fgetc(FILE *stream);  //按字符读取数据,一次只能读取一个字节的数据
      返回值:读取到的那个字符的ASCII码值
              失败 -1
int fputc(int c, FILE *stream);  //把c这个字符写入到stream表示的文件中


char *gets(char *s);  //只能读取键盘输入的字符串,把字符串保存到s中
int puts(const char *s) //把s这个字符串在标准输出(液晶屏)上打印出来

int getc(FILE *stream);   //按字符读取数据,一次只能读取一个字节的数据
int putc(int c, FILE *stream);  //把c这个字符写入到stream表示的文件中

int getchar(void);       //从IO缓冲区读取一个字符
int putchar(int c);      //把c代表的字符在液晶屏上打印出来

示例代码:

(1) fgets按行读取数据
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>

/*
    fgets按行读取文件
        特点:fgets遇到回车就结束读取,并且会把回车也读取出来
        特点:   假如一行只有10个字符
                   fgets(buf,5,myfile); //只能读取4个有效字符,最后一个fgets会填充\0
                   fgets(buf,11,myfile); //前面10个是有效字符,第11个是\0
                   fgets(buf,12,myfile); //前面11个是有效字符(会把回车\n读取,windows上的回车是\r\n),第12个是\0
*/
int main(int argc, char const *argv[])
{
    char buf[100] = {0};
    int ret = 0;
    FILE *fp1 = fopen("1.txt", "r+");
    if (fp1 == NULL)
    {
        perror("打开文件失败\n");
        return -1;
    }

    // 每一轮读取一行数据 
    // for (int i = 0; i < 3; i++)
    // {
        // bzero(buf, 0);
    //     fgets(buf, 100, fp1);
    //     printf("buf :%s\n", buf);
    // }
/* 
原始数据:
    helloworld
    你好
    你最棒 
执行结果:
    buf :helloworld

    buf :你好

    buf :你最棒 
    
*/
    // 第二个参数需要设置到足够大,否则一直读取第一行数据直至读完才会读取第二行数据
    bzero(buf, 100);
    fgets(buf,5,fp1);
    printf("buf :%s\n", buf);

    bzero(buf, 100);
    fgets(buf,5,fp1);
    printf("buf :%s\n", buf);

    bzero(buf, 100);
    fgets(buf,5,fp1);
    printf("buf :%s\n", buf);
/* 
原始数据:
    helloworld
    nihaonihao
    helloworld
执行结果:
    buf :hell
    buf :owor
    buf :ld
*/
    // 关闭文件
    fclose(fp1);

    return 0;
}

(2) fputs写入数据到文件
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>

int main(int argc, char const *argv[])
{
    char buf[100] = {0};
    int ret = 0;
    FILE *fp1 = fopen("1.txt", "r+");
    if (fp1 == NULL)
    {
        perror("打开文件失败\n");
        return -1;
    }
    // 写入字符串
    fputs("hello", fp1);
    fputs("world", fp1);
    fseek(fp1, 0, SEEK_SET);
    fread(buf, 1, 100, fp1);
    printf("buf:%s\n", buf);
    // 关闭文件
    fclose(fp1);

    return 0;
}
(3) fgets和fputs另外一个功能(标准输入和标准输出)
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>

int main(int argc, char const *argv[])
{
    char buf[100] = {0};
    // fgets读取键盘输入的字符串(标准输入)
    printf("fgets从键盘输入一个字符串:");
    fgets(buf, 100, stdin);
    // fputs写入字符串到液晶屏(标准输出)
    printf("fputs从液晶屏输出一个字符串:");
    fputs(buf, stdout);

    return 0;
}

/* 
执行结果:
    fgets从键盘输入一个字符串:nihao
    fputs从液晶屏输出一个字符串:nihao 
*/
(4) fgetc读取一个字符和fputc写入一个字符
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>

int main(int argc, char const *argv[])
{
    char buf[100] = {0};
    int ret = 0;
    FILE *fp1 = fopen("1.txt", "r+");
    if (fp1 == NULL)
    {
        perror("打开文件失败\n");
        return -1;
    }
    // 读取一个字节
    ret = fgetc(fp1);
    printf("读取到的内容:%c, %d\n", ret, ret);  // 读取到的内容:h, 104

    fputc('#', fp1);
    fseek(fp1, 0, SEEK_SET);
    fread(buf, 1, 100, fp1);
    printf("写入#后的内容是:%s\n", buf); // 写入#后的内容是:h#lloworld

    // 关闭文件
    fclose(fp1);

    return 0;
}

5、判断是否到达文件末尾

int feof(FILE *stream);
  返回值:1 表示达到文件末尾

示例代码:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>

int main(int argc, char const *argv[])
{
    char buf[100] = {0};
    FILE *fp = fopen("1.txt", "r+");
    if (fp == NULL)
    {
        perror("打开文件失败\n");
        return -1;
    }
    while(1)
    {
        bzero(buf, 100);
        char *ret = fgets(buf, 100, fp);
        printf("读取到一行的数据:%s\n", buf);
        // 方法1:通过fgets和fread的返回值判断
        // if (ret == NULL)
        // {
        //     printf("读取完毕\n");
        //     break;
        // }
        // 方法2:使用feof函数判断
        if (feof(fp) == 1)
        {
            printf("读取完毕\n");
            break;
        }
    }

    fclose(fp);

    return 0;
}

/* 执行结果:
    读取到一行的数据:h#lloworld

    读取到一行的数据:nihao

    读取到一行的数据:666666
    读取完毕 */

6、fprintf和fscanf()

   sprintf 拼接字符串
   printf  打印字符串
int fprintf(FILE *stream, const char *format, ...);  //按照指定格式,把数据合并写入到stream代表的文件中

int fscanf(FILE *stream, const char *format, ...);  //按照指定格式,把数据读取出来
   fscanf读取指定格式的数据
如果指定的格式是%s,fscanf会把整个文件内容都当成是字符串

示例代码:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>

int main(int argc, char const *argv[])
{
    /* fprintf 把字符串拼接好写入指定的文件中 */
    char read_buf[100] = {0};
    char *buf = "hello";
    int year = 2025;
    float score = 99.9;
    FILE *fp = fopen("2.txt", "w+");
    if (fp == NULL)
    {
        perror("打开文件失败\n");
        return -1;
    }
    fprintf(fp, "%s%d-%f", buf, year, score);
    // 写完后此时光标移至末尾,需要将光标重新移至开头
    fseek(fp, 0, SEEK_SET);
    // 读取文件
    fread(read_buf, 1, 100, fp);
    printf("read_buf:%s\n", read_buf); // read_buf:hello2025-99.900002
    // 关闭文件
    fclose(fp);

    /* fscanf 把文件中的内容读取并拆分 */
    char *write_buf = "2025-01-01";
    int y,m,d;
    FILE *fp2 = fopen("3.txt", "w+");
    if (fp2 == NULL)
    {
        perror("打开文件失败\n");
        return -1;
    }
    // 写入文件
    fwrite(write_buf, 1, strlen(write_buf), fp2);
    // 写入文件时会将光标移至文件末尾。需要将光标重新移至开头
    fseek(fp2, 0, SEEK_SET);
    // 把文件中的内容读取并拆分
    fscanf(fp2, "%d-%d-%d", &y, &m, &d);
    printf("年:%d\n", y);
    printf("月:%d\n", m);
    printf("日:%d\n", d);

    return 0;
}
/* 
执行结果:
    read_buf:hello2025-99.900002
    年:2025
    月:1
    日:1 
*/

7、主动刷新缓冲区

正常情况下标准IO是带缓冲区:
       情况一:缓冲区满了,自动刷新
       情况二:缓冲区没有满,主函数return退出的时候也会自动刷新缓冲区
       情况三:fclose关闭文件的时候也会刷新缓冲区
int fflush(FILE *stream);
    返回值:成功:0   失败:-1

示例代码:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>

int main(int argc, char const *argv[])
{
    int n = 0;
    FILE *fp = fopen("4.txt", "r+");
    if (fp == NULL)
    {
        perror("打开文件失败\n");
        return -1;
    }
    while (1)
    {
        fwrite("hello", 1, 5, fp);
        sleep(1);
        fflush(fp); // 主动刷新缓冲区
    }
    fclose(fp);
    // return 0;
}

二、对比系统IO和标准IO的区别

1、

  • 系统IO采用文件描述符来表示文件
  • 标准IO采用FILE*来表示文件

2、

 系统IO        0         1            2
               #define  STDIN_FILENO        0    标准输入--》键盘
               #define  STDOUT_FILENO       1    标准输出--》液晶屏
               #define  STDERR_FILENO       2    标准错误输出--》液晶屏
 标准IO       stdin   stdout      stderr
               FILE *stdin;          标准输入--》键盘
               FILE *stdout;         标准输出--》液晶屏  
               FILE *stderr;         标准错误输出--》液晶屏

3、

  • 系统IO没有缓冲区
  • 标准IO带缓冲区

相关文章:

  • SpringBoot集成Couchbase开发与实践
  • 使用 docker compse 启动 Milvus 修改 MINIO_ACCESS_KEY 导致启动失败
  • onedav一为导航批量自动化导入网址(完整教程)
  • 回归——数学公式推导全过程
  • //TODO 动态代理的本质?
  • 深度学习与计算机视觉方向
  • MATLAB实现基于“蚁群算法”的AMR路径规划
  • 蓝桥杯 回文数组
  • 常见中间件漏洞之四:Apache
  • 通信基本概念
  • windows切换系统版本
  • 【uni-app】tabBar使用
  • Python中json和jsonify的使用
  • 【MySQL】锁机制
  • DeepSeek技术架构解析:MoE混合专家模型
  • C语言-桥接模式详解与实践
  • 清华大学大模型智能体自我认知与决策流程!自知、反思、规划:城市环境目标导航中的大模型智能体新范式
  • 驱动开发的引入
  • k8s中运行nginx的亲和性
  • BigEvent项目后端学习笔记(二)文章分类模块 | 文章分类增删改查全流程解析(含优化)
  • 曾犯强奸罪教师出狱后办教培机构?柳州鱼峰区教育局回应
  • 科普|男性这个器官晚到岗,可能影响生育能力
  • 秦洪看盘|指标股发力,A股渐有突破态势
  • 商人运作亿元“茅台酒庞氏骗局”,俩客户自认受害人不服“从犯”判决提申诉
  • 让胖东来“自闭”的玉石生意,究竟水有多深?
  • 成就彼此,照亮世界:“中欧建交50周年论坛”在沪成功举行