Linux中的标准IO【上】

标准IO
  • fopen()
    • FILE * fopen(const char * restrict path, const char * restrict mode);
    • 第一个参数表示被打开文件路径,第二个参数表示打开文件模式—模式不同,对同一个文件有不同的更改
    • r和r+模式下不存在文件则也无法创建,其余模式若文件本就不存在可以先创建后读取
    • const修饰用户无法修改对应参数
      char *ptr = "abc";
      ptr[0] = "x";
      // 是否正确?
      // linux下不正确因为其是字符串常量因此不可用修改
    
    • 成功后会返回一个FILE指针,如果失败则返回空指针并将errno进行设置
    • errno在未被设置时是一个全局变量,出错后会将出错信息放在这个上面
    • 补充两个函数—将errno的数字转换成message
      • perror(“fopen:”)—报错系统具体信息,在串后加入出错信息
      • char *strerror(int errno)—#include<string.h>
      • fprintf(stderr, “fopen():%s\n”, strerror(errno));
    • 辨析stderr报错和perror报错信息
      • fprintf(stderr, “Usage…\n”);
      • 这行代码使用了C语言标准库中的fprintf函数来向标准错误输出流(stderr)打印一条消息,消息内容为"Usage…"。通常,这种语句用于显示程序的使用方法或错误消息,以便用户可以了解如何正确使用程序或了解程序运行中的错误信息。在这种情况下,将消息输出到stderr流可以确保消息不会与程序的标准输出混淆,而是会被重定向到标准错误输出(通常是终端窗口)中。
      • perror(“stat()”);
      • 这行代码使用了C语言标准库中的perror函数,用于将最近一次发生的错误信息输出到标准错误流(stderr)中。在这个例子中,perror(“stat()”)将输出一个类似于"stat(): No such file or directory"的错误信息,指示最近一次执行的stat函数失败,并指明失败的原因为"文件或目录不存在"。
      • 通常,perror函数在程序中用于处理系统调用或库函数失败的情况,以便向用户提供更有意义的错误信息。输出的错误信息中包含了错误代码和对应的错误信息,可以帮助程序员快速定位程序出错的原因。
    • 两种报错方式的不同
      • 输出位置不同:fprintf函数输出错误信息到标准错误流(stderr),而perror函数直接将错误信息输出到标准错误流中。
      • 输出内容不同:fprintf函数可以输出任何指定格式的错误信息,包括自定义错误信息和变量值,而perror函数只输出最近一次系统调用或库函数失败的错误信息,通常包含错误代码和对应的错误信息。
      • 方便程度不同:使用fprintf函数输出错误信息需要自己组织错误信息的格式和内容,而perror函数可以直接输出系统调用或库函数失败的错误信息,方便快捷。
    • linux中stdin,stdout,stderr
      • stdout, stdin, stderr的中文名字分别是标准输出,标准输入和标准错误
      • 在Linux下,当一个用户进程被创建的时候,系统会自动为该进程创建三个数据流,也就是题目中所提到的这三个。那么什么是数据流呢(stream)?我们知道,一个程序要运行,需要有输入、输出,如果出错,还要能表现出自身的错误。这是就要从某个地方读入数据、将数据输出到某个地方,这就够成了数据流。
      • 因此,一个进程初期所拥有的这么三个数据流,就分别是标准输出、标准输入和标准错误,分别用stdout, stdin, stderr来表示。对于这三个数据流来说,默认是表现在用户终端上的。
  • 回顾知识点
    • 什么样的数据类型在堆、栈及静态区
      • 堆—一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收。
      • 栈—由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。
      • 静态区(全局区)—全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域, 未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。有一大特点如果被多次声明,其只分配一块区域,这就需要你在访问该类变量的过程中,只能对一块区域进行操作。这就导致变量相同的只能访问一个。
  • 问题—fopen()是在哪里呢?—堆上—简单来说—一般情况下有互逆操作的都在堆上
    • fclose()—关闭一个流
      • int fclose(FILE *fp)
    • fgetc()
      • int fgetc(FILE *stream)// 与getc相同,EOF则存在报错—其实是一个函数
      • 注意返回是int,不是char
      • int getc(FILE *stream)// 与getchar等价,可以在任意流中获得内容—其实是一个宏
      • 宏和函数的区别
        • 宏只占用编译时间,不占用调用时间
    • fputc()
      • int fputc(int c, FILE *stream)
      • int putc(int c, FILE *stream)//返回值是int
      //需求分析---命令行实现将一个文件拷贝进入另一个文件
      #include<stdio.h>
      #include<stdlib.h>
      int main(int argc, char** argv){
        FILE *fpo, *fpc;
        int ch;//观察是否读取到文件内容,也可以判断是否达到文件读取的底部
        if(argc < 3){
          fprintf(stderr, "Usage: %s, <src_file>, <dest_file>", argv[0]);
        }
        fpo = fopen(argv[1], "r");
        if(fpo == NULL){
          perror("fopen()");
          exit(1);
        }
        fpc = fopen(argv[2], "w");
        if(fpc == NULL)	
          {
            fclose(fpo);//防止内存泄漏
            perror("fopen()");
            exit(1);
          }
        while (1)
        {
          ch = fgetc(fpo);
          if (ch == EOF){
            break;
          }
          fputc(ch, fpc);//将ch放入fpc
        }
        fclose(fpc);//先删除依赖
        fclose(fpo);
        exit(0);
      }
    
    • 补充知识点
      • 如何将命令行参数转换为主函数的参数
      //int main(int argc, char **argv)
      //argc是命令行有几个参数输入的总量,argv则是一个数组,下标从1开始就是第一个参数
    
    • fgets()
      • gets()不检查缓冲区的溢出情况,只约束了地址,不检查终端最后输入地址时是否够放入存储的空间。因此,使用fgets()更好
      • char *gets(char *s)//只有地址不检查当前输入长度
      • char *fgets(char *s, int size, FILE *stream)//有长度检查功能,读到size-1个字符,而后有一个’\n’
      • fgets有两种可能结束
        • 读到size-1个
        • 读到’\n’
      • 使用fgets输入一个"ab",则真正存储的是"ab\0",而每次读取结束的标志是要存在\n,可以理解为只有\n被读取才能证明该流被读取完
        // 试判断abcd这个流需要几次才能用以下的fgets读取成功
        #define SIZE 5
        fgets(buf, SIZE, stream);
        // 答案---两次
        // 第一次---abcd\0 注意但并未读到\n
        // 第二次---\n\0...读取完成
        // 读取完成后为NULL
      
    • fputs()
      • int puts(const char *s)//遇到\0为止
      • int fputs(const char *s, FILE *stream)
    • fread()
      • size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream)
        • 解读—在stream读入ptr,读入nmemb个对象,每个对象大小为size,因此,ptr大小为nmemb*size
      • 返回值其实就是读取了多少个对象nmemb
    • fwrite()
      • size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
    • 这两个函数没有边界验证,只能操作比较整齐的数据,为了保险起见一般size我们选择1字节。退化为fgetc使用。可以从下面这个例子来看。
      fread(buf, size, nmemb, fp);
      1->数据量足够
      2->只有5个字节
      fread(buf, 1, 10, fp);
      1->10->10字节
      2->5->5字节
      fread(buf, 10, 1, fp);
      1->1->10字节
      2->0->??   
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值