【从零开始的嵌入式生活】文件I/O1——标准I/O

请添加图片描述

今天正式进入应用层的学习,那么梦开始的地方就是文件I/O,接下来几天的时间都会围绕这部分内容展开,主要内容如下:
请添加图片描述

三连即可提高学习效率

🧑🏻作者简介:一个学嵌入式的年轻人
✨联系方式:2201891280(QQ)
📔源码地址:https://gitee.com/xingleigao/study_qianrushi
全文大约阅读时间: 120min



文件基础

在Linux下,一切皆文件

概念: 一组相关数据的有序集合
文件类型:

  • 常规文件 r
  • 目录文件 d
  • 字符设备文件 c(输入输出设备)
  • 块设备文件 b(输入输出设备)
  • 管道文件 p(进程通信)
  • 套接字文件 s(网络编程)
  • 符号链接文件 l(类似于快捷方式)

在这里插入图片描述


系统调用相关和库函数的关系
内核实现了硬件和软件的隔离。
请添加图片描述


标准I/O

介绍

标准I/O由ANSI C标准定义
主流操作系统上都实现了C库
标准I/O通过缓冲机制减少系统调用,实现更高的效率(比如我们熟知的printf就是行缓冲。如果不\n就可能出错之前输出不了)


  • FILE
    标准IO用一个结构体类型来存放打开的文件的相关信息
    标准I/O的所有操作都是围绕FILE来进行
  • 流(stream)
    FILE又被称为流(stream)
    文本流/二进制流

windows和Linux文件的区别
Windows:

  • 二进制流: 换行符: ‘\n’
  • 文本流: 换行符 :‘\r’ ‘\n’

Linux

  • 换行符 : ‘\n’

流的缓冲类型

  • 全缓冲
    当流的缓冲区无数据或无空间时才执行实际I/O操作
  • 行缓冲(printf scnaf)
    当在输入和输出中遇到换行符(‘\n’)时,进行I/O操作
    当流和一个终端关联时,典型的行缓冲
  • 无缓冲(ttl)
    数据直接写入文件,流不进行缓冲

三个特殊流

名称文件描述符文件指针
标准输入流0STDIN_FILENOstdin
标准输出流1STDOUT_FILENOstdout
标准错误流2STDERR_FILENOstderr

错误流默认无缓冲,stdin和stdout是行缓冲。


可以用下面的代码看print的缓存大小:

#include <stdio.h>
#include <stdlib.h>
#define N 100

int main(int argc, const char *argv[]){
       int i;
       char a = 'a';

       if(argc != 2){
               printf("Usage:%s Number\n",argv[0]);
               return 0;
       }
       for(i = 0; i < atoi(argv[1]);++i)
               printf("%c",a);

       while(1);
       return 0;

}

打开和关闭流

打开文件

FILE *fopen (const char *path, const char *mode);

成功返回指针
关于mode函数

参数含义
”r"、“rb”以只读方式文件,文件必须存在。
“r+”、“r+b”以读写方式打开文件,文件必须存在
“w”、“wb”以只写方式打开文件,若文件存在则文件长度清0。不存在则创建。
”w+"、“w+b”以读写方式打开文件,其他同"w"
“a"、“ab”以只写方式打开文件,若文件不存在创建;向文件写入的数据被追加到文件末尾。
“a+”、“a+b”以读写方式打开文件。其他同"a"

新建文件权限
fopen() 创建的文件访问权限是0666(rw-rw-rw-)
Linux系统中umask设定会影响文件的访问权限,其规则为(0666 & ~umask)
Root用户是 022 普通用户是002
其实就是0666-022
用户可以通过umask函数或者命令修改相关设定
相关示例代码在:/io/1.stand_io/2.open_close/2.fopen.c


处理错误信息

extern int  errno;
void perror(const char *s);
char *strerror(int errno);
  • errno 存放错误号,由系统生成
  • perror先输出字符串s,再输出错误号对应的错误信息
  • strerror根据错误号返回对应的错误信息

相关示例代码在:/io/1.stand_io/2.open_close/2.perror.c

关闭文件流

int fclose(FILE *stream)
  • fclose()调用成功返回0,失败返回EOF,并设置errno
  • 流关闭时自动刷新缓冲中的数据并释放缓冲区
  • 当一个程序正常终止时,所有打开的流都会被关闭。
  • 流一旦关闭后就不能执行任何操作

相关示例代码在:/io/1.stand_io/2.open_close/2.close.c


程序中能够打开的文件或流的个数有限制,如何测试?

思路:循环打开流,成功则计数器累加,直到出错为止
示例代码/io/1.stand_io/2.open_close/2.fopen_num.c
每个程序默认有三个打开表项,就是stdinstdoutstderror三个文件
所以最多的就是1024-3 = 1021

流操作

字符的输入输出

字符的输入

#include <stdio.h>
int fgetc(FILE *stream);
int getc(FILE *stream); //宏
int getchar(void);
  • 成功时返回读取的字符;若到文件末尾或出错时返回EOF
  • getchar()等同于fgetc(stdin)
  • getc和fgetc区别是一个是宏一个是函数

建议使用fgetc()
示例代码:

#include <stdio.h>

int main(){

       char ch;

       ch = fgetc(stdin);

       printf("read char:%c\n",ch);
       return 0;
}

如果是从文件读入就是:

#include <stdio.h>

int main(){

      char ch;
      FILE *fp;
      fp = fopen("1.txt","r");
      if(fp != NULL){
              ch = fgetc(fp);

              printf("read char:%c\n",ch);
      }else{
              perror("open");
      }
      return 0;
}

字符的输出

#include  <stdio.h>
int  fputc(int c, FILE *stream);
int  putc(int c, FILE *stream);
int  putchar(int c);
  • 成功时返回写入的字符;出错时返回EOF
  • putchar©等同于fputc(c, stdout)
    相关示例代码在/io/1.stand_io/2.open_close

思考题:
如何利用fgetc / fputc实现文件的复制?

通过命令行参数传递源文件和目标文件名
通过fgetc返回值判断是否读到文件末尾
示例代码在io/1.stand_io/2.open_close/fgetc_fputc_copy.c
补充一个命令:diff 1.txt 2.txt可以对比两个文件的差异。


行输入输出

字符的输入

#include  <stdio.h>
char  *gets(char *s);//不要用!!!!!
char *fgets(char *s, int size, FILE *stream);

成功时返回s,到文件末尾或出错时返回NULL
gets不推荐使用,容易造成缓冲区溢出已经被废除!
遇到’\n’或已输入size-1个字符时返回,总是包含’\0’


字符的输出

#include  <stdio.h>
int  puts(const char *s);
int fputs(const char *s,  FILE *stream);

成功时返回输出的字符个数;出错时返回EOF
puts将缓冲区s中的字符串输出到stdout,并追加’\n’
fputs将缓冲区s中的字符串输出到stream,不追加 ‘\n’


对象的输入输出

#include  <stdio.h>
size_t fread(void *ptr, size_t size, size_t n, FILE *fp);
size_t fwrite(const void *ptr, size_t size, size_t n, FILE *fp);

成功返回读写的对象个数;出错时返回EOF
既可以读写文本文件,也可以读写数据文件
效率高
相关的操作在/io/1.stand_io/2.open_close

刷新流和定位

刷新流

#include <stdio.h>
int fflush(FILE *fp);

成功时返回0;出错时返回EOF
将流缓冲区中的数据写入实际的文件
Linux下只能刷新输出缓冲区,输入缓冲区丢弃
示例代码

#include <stdio.h>

int main(){

       int i = 0;
       for(i = 0; i < 100; ++i){
               printf("a");
               fflush(stdout);
       }

       while(1);
       return 0;
}

定位流

看下图,当进行写操作的时候,我们的指针会不断的往后走,如果我们想要回到b的位置进行重写,就是流定位。请添加图片描述

#include  <stdio.h>
long ftell(FILE *stream);
long fseek(FILE *stream, long offset,  int whence);
void rewind(FILE *stream);//回到文件头

ftell() 成功时返回流的当前读写位置,出错时返回EOF
fseek()定位一个流,成功时返回0,出错时返回EOF
whence参数:SEEK_SET/SEEK_CUR/SEEK_END
示例程序:

#include <stdio.h>

int main(){

       FILE *fp;
       int st;
       char buf[16];
       fp = fopen("1.txt","a+");
       if(fp){
               st = ftell(fp);
               printf("st:%d\n", st);

               fputs("abcd",fp);

               st = ftell(fp);
               printf("st:%d\n", st);

               //fseek(fp, 1, SEEK_SET);
               rewind(fp);
               fgets(buf, 5, fp);
               printf("buf:%s\n",buf);
       }
       return 0;
}

判断流是否出错和结束

#include  <stdio.h>
int ferror(FILE *stream);
int feof(FILE *stream);
  • ferror()返回1表示流出错;否则返回0
  • feof()返回1表示文件已到末尾;否则返回0

格式化输出和输入

格式化输出

#include  <stdio.h>
int printf(const char *fmt,);
int fprintf(FILE *stream, const char *fmt,);
int sprintf(char *s, const char *fmt,);

成功时返回输出的字符个数;出错时返回EOF
使用起来很方便,强烈推荐!
示例代码详见:/io/1.stand_io/2.open_close/sprintf.c


格式化输入

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

示例代码详见:/io/1.stand_io/2.open_close/scanf.c


思考和练习

每隔1秒向文件test.txt中写入当前系统时间,格式如下:

1,  2014-10-15 15:16:42
2,  2014-10-15 15:16:43

该程序无限循环,直到按Ctrl-C中断程序

提示:

  1. time()用来获取系统时间(秒数)
  2. localtime()将系统时间转换成本地时间
  3. sleep()实现程序睡眠
    示例代码:/io/1.stand_io/2.open_close/demo.c

写在最后

文件IO没特别多的东西,今天已经过了一大半了,明天我就会更新完,我尽量一天一更,大家和我一起变强呀!最后三连即可提高学习效率!!!


另外我在更新的就是算法笔记的一些例题笔记,这个系列是用于提高我的算法能力,如果有兴趣对算法领域感兴趣找不到合适的入门文章也可以追更,如果我更新的太慢了请大家点赞收藏,一键三连才能更有更新的动力呀0.0

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

XingleiGao

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值