I\O进程线程(Day27)

embedded/2024/10/15 22:01:43/

一、学习内容

  1. IO基础

    1. 概念

      程序与外部设备进行交换的信息过程

    2. 分类

      1. 标准IO
        封装好的相关库函数、有缓冲区、文件指针eg:fprintf、fscanf、fputc、fgetc、fputs、fgets、fopen、fclose...
        1. 操作流程
          FILE *fp通过fopen打开文件 使用fprintf、fputc、fputs、fwrite把在程序的结果写入文件中进行保存 使用fscanf、fgetc、fgets、fread把在文件中的数据读取到程序运行
      2. 文件IO
        系统(内核)提供的相关函数,无缓冲区、文件描述符eg:open、close、read、write、seek...
  2. 标准IO

    • 提供的数据类

      • FILE文件结构体类型
        • 缓冲区
          • 缓冲区开始地址
            char * _IO_buf_base;
          • 缓冲区结束地址
            char *_IO_buf_end;
          • 类型
            • 行缓存

              • 概念

                标准输入、输出指针(stdin、stdout)对应缓冲区,大小为1024字节
              • 刷新时机

                • 换行刷新

                • 程序结束后刷新

                • 文件指针关闭后刷新

                • 使用后fflush刷新文件指针后回刷新

                • 输入输出切换后刷新

                • 缓存区满会刷新(满了1024字节数据后再放数据进去,刷新行缓存,释放1024字节的数据,等再有如此情况出现会再次刷新行缓存,释放数据)

            • 全缓存

              • 概念

                普通文件指针(FILE *fp)对应缓存,大小为4096字节
              • 刷新时机

                • 程序结束后刷新

                • 文件指针关闭后刷新

                • 使用fflush函数

                • 输入和输出切换时刷新

                • 缓存区满了后再添加数据会先释放先前的4096字节再添加新的数据

            • 不缓存

              • 概念

                标准出错文件指针对应缓冲区,大小为0
      • 文件指针
        • stdin(标准输入指针)
        • stdout(标准输出指针)
        • stderr(标准出错指针)
    • fopen(打开文件)

      FILE *fopen(const char *pathname, const char *mode);
      • 返回值
        成功返回打开的文件地址 失败返回NULL
      • 参数
        • 参数1:要打开文件的路径
        • 参数2:文件打开的方式
          • r
            只读形式,读光标在开头,不存在就报错
          • r+
            读写形式,读写光标在一起且在开头,不存在就报错
          • w
            只写形式,文件存在就清空文件,不存在就创建该文件,光标在开头
          • w+
            读写形式,文件存在就清空文件,不存在就创建该文件,读写光标都在开头
          • a
            追加形式,文件不存就创建该文件,光标在文件结尾
          • a+
            读或追加形式,文件不存在就创建该文件,第一次读数据光标在开头,否则读写光标都在末尾
      • 功能
        用指定方式打开一个指定文件,并返回该文件的地址
    • fclose(关闭文件)

      int fclose(FILE *stream)
      • 返回值
        成功返回0 失败返回EOF
      • 参数
        要关闭的文件指针
      • 功能
        关闭给定文件指针
    • fgetc\fputc(单字符的输入和输出)

      • fputc
        int fputc(int c,FILE *stream)
        • 返回值
          成功返回写入字符的ascii值 失败返回EOF
        • 参数
          参数1:要写入的字符串
          参数2:打开的文件指针
        • 功能
          把字符写入到文件指针stream指向的文件中
      • fgetc
        int fgetc(FILE *stream)
        • 返回值
          成功返回ascii值 失败返回EOF
        • 参数
          打开文件的指针
        • 功能
          从给定的文件中读取一个字符
    • 错误码

      • 概念
        内核空间函数调用出问题时,内核空间会向用户空间反馈一个错误信息,为了方便查看错误信息,将这些错误信息进行编号,这个错误号码就叫做错误码
      • 函数strerror
        char *strerror(int errnum);
        • 返回值
          错误码对应的错误信息
        • 参数
          错误码
        • 功能
          将给定的错误码,转变成错误信息
      • perror函数
        void perror(const char *s)
        • 无返回值
        • 参数
          提示字符串,会自动提供一个冒号输出结束后会自己加一个换行符
        • 功能
          向标准错误缓冲区写入最新的错误码所对应的错误信息
    • fputs\fgets(字符串输入输出)

      • fputs
        int fputs(const char *s, FILE *stream);
        • 返回值
          成功犯规写入字符个数(字符串长度) 失败返回EOF
        • 参数
          参数一:要写入的字符串的起始地址
          参数二:打开文件的指针
        • 功能
          将给定的字符串写入到指定的文件中
      • fgets
        char *fgets(char *s, int size, FILE *stream);
        • 返回值
          成功返回容器的起始地址 失败返回NULL
        • 参数
          参数1:存放数据所用的容器
          参数2:读取的大小
          参数3:文件指针
        • 功能
          从stream所指向的文件中,最多读取size-1的字符带s中,读取过程中遇到回车或者文件结束,会结束本次读取,回车也会被写入到s容器中,并在s容器的结尾加上'\0'
    • 系统时间函数

      • time_t time(time_t *tloc);
        • 功能
          获取从1970年1月1日0时0分0秒,到目前累计的秒数
        • 参数
          用于接收的秒数
        • 返回值
          秒数
        • 使用方式
          • 使用方式1: time_t sys_time = time(NULL)
          • 使用方式2: time_t sys_time = 0; time(&sys_time);
      • struct tm *localtime(const time_t *timep);
        • 功能
          将time_t 秒数,转换为时间类型的结构体
        • 参数
          time_t 类型的时间秒数
        • 返回值
          时间结构体
    • sprintf\snprintf(将格式串转换为字符串)

      • sprintf
        int sprintf(char *str, const char *format, ...);
        • 返回值
          成功返回转换的字符个数,失败返回-1
        • 参数
          参数1:存放格式串的字符数组
          参数2:格式串,可以包含格式控制符
          参数3:可变参数,根据参数2中的格式控制符个数确定
        • 功能
          将格式串转换为字符串放入字符数组中
      • snprintf
        int snprintf(char *str, size_t size, const char *format, ...);比sprintf更加安全,因为多了一个size的限制其余相同
    • fprintf\fscanf(格式化读写函数)

      • fprintf
        int fprintf(FILE *stream, const char *format, ...);
        • 返回值
          成功返回写入文件的字符实际个数 失败返回-1
        • 参数
          参数1:文件指针
          参数2:格式串,可以包含格式控制符
          参数3:可变参数,根据参数2而定
        • 功能
          向指定文件中写入一个格式串
      • fscanf
        int fscanf(FILE *stream, const char *format, ...);
        • 返回值
          成功返回读取数据的个数 失败返回EOF
        • 参数
          参数1:文件指针
          参数2:格式串,可以包含格式控制符
          参数3:可变参数,根据参数2而定
        • 功能
          从指定文件中读取一些数据放入程序中
    • fread\fwrite(模块化读写)

      • fread
        size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
        • 返回值
          成功读取返回本次读取的项数值 失败返回一个小于项数的数字
        • 参数
          参数1:要读取的数据的起始地址,万能指针,可以写入任意类型的数据
          参数2:每一项数据的大小
          参数3:要读取数据的总项数
          参数4:要被读取的文件
        • 功能
          从stream文件中读取nmemb项数据,每项数据大小为size,将读取出来的数据放入ptr指向的容器中
      • fwrite
        size_t fwrite(const void *ptr, size_t size, size_t nmemb,FILE *stream)
        • 返回值
          成功写入返回本次写入的项数值 失败返回一个小于项数的数字
        • 参数
          参数1:要写入的数据的起始地址,万能指针,可以写入任意类型的数据
          参数2:每一项数据的大小
          参数3:要写入数据的总项数参数4:要被写入的文件
        • 功能
          将起始地址为ptr的nmemb项数据(每一项的大小为size),写入到stream文件中
  3. 脑图

二、作业

1> 使用fread和fwrite完成两个文件的拷贝,要求源文件和目标文件由外界输入

代码解答:

#include <myhead.h>  
#define BUFFER_SIZE 1024  // 定义缓冲区大小为 1024 字节int main(int argc, const char *argv[])
{FILE *source = NULL;  // 文件指针,用于源文件FILE *dest = NULL;    // 文件指针,用于目标文件// 检查命令行参数个数是否至少包含源文件和目标文件两个参数if (argc < 3) {fprintf(stderr, "Usage: %s <source file> <destination file>\n", argv[0]);  // 提示正确使用方法return -1;  // 返回错误代码 -1}// 打开源文件if ((source = fopen(argv[1], "r")) == NULL) {perror("fopen source error");  // 打印源文件打开失败的错误信息return -1;  // 返回错误代码 -1}// 打开目标文件if ((dest = fopen(argv[2], "w+")) == NULL) {perror("fopen dest error");  // 打印目标文件打开失败的错误信息fclose(source);  // 关闭已经成功打开的源文件return -1;  // 返回错误代码 -1}size_t a;  // 用于存储 fread 返回的已读取字节数char buffer[BUFFER_SIZE];  // 定义缓冲区,用于存储每次从源文件读取的内容// 循环从源文件中读取数据,每次最多读取 BUFFER_SIZE 字节,直到读到文件末尾while ((a = fread(buffer, 1, BUFFER_SIZE, source)) > 0) {// 将从源文件中读取的 a 字节数据写入目标文件fwrite(buffer, 1, a, dest);}// 关闭源文件和目标文件,确保资源被释放fclose(source);fclose(dest);// 打印文件拷贝完成的提示信息printf("文件拷贝完成。\n");return 0;  // 正常结束程序
}

效果图展示:

2> 使用fgets获取当前文件的总行数

代码解答:

#include <myhead.h>
#define BUFFER_SIZE 1024
int main(int argc, const char *argv[])
{FILE *fp=NULL;if((fp=fopen("./file.txt","r"))==NULL){perror("fopen error");return -1;}char buffer[BUFFER_SIZE];int line_count=0;while(1){char *res=fgets(buffer,BUFFER_SIZE,fp);if(res==NULL){break;}line_count++;}fclose(fp);printf("文件有%d行",line_count);return 0;
}

效果图展示:

3> 向文件中每一秒打印当前系统时间同时也在终端上面显示

例如:

1、17:10:30
2、17:10:31
3、17:10:32
ctrl +c结束程序
./a.out
4、17:20:15
5、17:20:16
注意前面的编号!!

代码解答:

#include <stdio.h>
#include <time.h>
#include <signal.h>volatile int stop = 0;  // 全局变量,用于控制程序停止// 处理 Ctrl+C 信号的函数
void handle_sigint(int sig) {stop = 1;  // 当接收到 Ctrl+C 信号时,将 stop 设置为 1 以终止循环
}int main() {FILE *file = fopen("output.txt", "a");  // 以追加模式打开文件if (file == NULL) {  // 检查文件是否成功打开perror("fopen error");return -1;}signal(SIGINT, handle_sigint);  // 注册信号处理函数,处理 Ctrl+Cint count = 1;  // 行编号time_t rawtime;  // 当前时间struct tm *timeinfo;  // 用于存储本地时间struct tm prev_timeinfo = {0};  // 用于存储前一秒的时间while (!stop) {  // 无限循环,直到 stop 被设置为 1time(&rawtime);  // 获取当前时间timeinfo = localtime(&rawtime);  // 转换为本地时间// 如果当前秒数与之前的秒数不同,说明已经过了一秒if (timeinfo->tm_sec != prev_timeinfo.tm_sec) {// 输出编号和时间到终端printf("%d、%04d-%02d-%02d %02d:%02d:%02d\n", count, timeinfo->tm_year + 1900,  // 年份timeinfo->tm_mon + 1,      // 月份timeinfo->tm_mday,         // 日timeinfo->tm_hour,         // 小时timeinfo->tm_min,          // 分钟timeinfo->tm_sec);         // 秒// 同样输出编号和时间到文件fprintf(file, "%d、%04d-%02d-%02d %02d:%02d:%02d\n", count, timeinfo->tm_year + 1900,  // 年份timeinfo->tm_mon + 1,      // 月份timeinfo->tm_mday,         // 日timeinfo->tm_hour,         // 小时timeinfo->tm_min,          // 分钟timeinfo->tm_sec);         // 秒fflush(file);  // 刷新文件缓冲区,确保数据立即写入count++;  // 编号自增prev_timeinfo = *timeinfo;  // 更新前一秒的时间}}fclose(file);  // 关闭文件printf("\n程序结束。\n");  // 打印结束信息return 0;  // 正常退出程序
}

效果图展示:

三、总结

学习内容概述:

        今天的学习重点是IO基础,主要包括标准IO和文件IO的操作流程及其使用方法。你学习了标准IO如何通过封装好的库函数与文件进行交互,以及文件IO如何通过系统提供的函数来进行无缓冲区的文件操作。此外,还涉及缓冲区的类型、文件指针的操作、字符与字符串的输入输出操作、错误码处理机制、系统时间函数、格式化读写函数、模块化读写等内容。

学习难点:

1. 缓冲区类型和刷新机制:

行缓存、全缓存、无缓存的概念及其刷新时机在实际操作中较为抽象,特别是如何正确管理和优化缓冲区的使用。

2. 文件指针与文件描述符的区别:

标准IO和文件IO的核心差异之一在于文件指针和文件描述符的使用,理解它们各自的应用场景需要通过更多的实践。

3. 系统时间函数的使用:

理解time()函数获取的时间戳以及如何转换为结构体时间格式是时间操作中容易混淆的部分。

主要事项:

1. 标准IO通过缓冲区来提升效率,缓冲区的类型和大小需要根据使用场景合理选择,并通过`fflush`等函数手动刷新缓冲区。

2. 文件操作时要注意不同模式(如`r`、`w`、`a`等)下的读写权限,以及文件打开失败后的错误处理(使用`strerror`或`perror`函数)。

3. 格式化输入输出函数(如`fprintf`、`fscanf`)和模块化读写函数(如`fread`、`fwrite`)的区别在于前者基于格式,后者基于数据块进行读写。

未来学习的重点:

1. 进一步理解和优化缓冲区管理:

在实际项目中,如何根据不同的场景选择行缓存、全缓存或无缓存,以提升程序的性能。

2. 深入掌握文件IO的应用场景:

在无缓冲区的文件IO操作中,深入理解文件描述符的作用,并学习如何进行高效的文件读写。

3. 实践系统时间和日期处理:

熟练掌握系统时间的获取和格式化输出,特别是涉及到跨平台的时间操作和时间戳处理。


http://www.ppmy.cn/embedded/128097.html

相关文章

STM32的独立看门狗定时器(IWDG)技术介绍

在嵌入式系统中&#xff0c;确保系统的稳定性和可靠性至关重要。看门狗定时器&#xff08;Watchdog Timer, WDT&#xff09; 是一种常用的硬件机制&#xff0c;用于监控系统的运行状态&#xff0c;防止系统因软件故障或意外情况进入不可预期的状态。STM32系列微控制器提供了两种…

力扣hot100--二叉树

二叉树 1. 94. 二叉树的中序遍历 给定一个二叉树的根节点 root &#xff0c;返回 它的 中序 遍历 。 示例 1&#xff1a; 输入&#xff1a;root [1,null,2,3] 输出&#xff1a;[1,3,2]示例 2&#xff1a; 输入&#xff1a;root [] 输出&#xff1a;[]示例 3&#xff1a; …

【银行科技岗】相关考试知识点总结及部分考题

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 一、**网络与安全**二、**软件开发与设计**三、**数据库与数据管理**四、**编程与系统**五、**计算机硬件与性能**六、**大数据与人工智能**七、**系统与应用**相关…

pdf阅读软件有哪些?5个软件帮助你快速进行pdf阅读

pdf阅读软件有哪些&#xff1f;5个软件帮助你快速进行pdf阅读 如果你正在寻找优秀的PDF阅读软件&#xff0c;以下推荐的5款软件能够帮助你快速、轻松地阅读和管理PDF文件。这些工具各具特色&#xff0c;适用于不同的使用需求&#xff0c;无论是注释、签名、还是管理大文件&…

基于Spring Boot REST API设计指南

在构建现代Web应用程序时&#xff0c;RESTful API已成为一种标准&#xff0c;使得不同的应用程序能够通过HTTP协议进行通信&#xff0c;实现资源的创建、读取、更新和删除等操作。Spring Boot作为一个功能强大的框架&#xff0c;能够轻松创建RESTful API。本文将详细介绍如何在…

非js脚本打开浏览器窗口的关闭解决方案

js脚本打开方式浏览器窗口 关闭方式&#xff1a; window.close() 非js脚本打开方式浏览器页面 只是前端开发者会惊奇的发现&#xff0c;使用window.close() API,并不能每次成功关闭浏览器窗口&#xff0c;打开控制台发现会有一条警告信息 错误分析&#xff1a; 为什么浏览…

企业在隔离网环境下如何进行安全又稳定的跨网文件交换?

在数字化时代&#xff0c;企业的数据流通如同血液一般重要。然而&#xff0c;当企业内部实施了隔离网环境&#xff0c;跨网文件交换就成了一个棘手的问题。今天我们将探讨在隔离网环境下&#xff0c;企业面临的跨网文件交换挑战&#xff0c;以及如何通过合规的跨网文件交换系统…

目录类QDir

Qt使用"/"来作为通用的目录分隔符&#xff0c;所以表示文件路径的字符串中我们最好用"/" 使用"/"&#xff0c;Qt会自动的转换你的路径来匹配你当前使用的操作系统 常用静态方法 获取当前项目所在的路径 [static] QString QDir::currentPath(…