I\O进程线程(Day27)

news2024/11/29 5:38:14

一、学习内容

  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+C

    int count = 1;  // 行编号
    time_t rawtime;  // 当前时间
    struct tm *timeinfo;  // 用于存储本地时间
    struct tm prev_timeinfo = {0};  // 用于存储前一秒的时间

    while (!stop) {  // 无限循环,直到 stop 被设置为 1
        time(&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.coloradmin.cn/o/2215898.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Linux】Linux进程概念

冯诺依曼体系结构 我们常见的计算机&#xff0c;如笔记本。我们不常见的计算机&#xff0c;如服务器&#xff0c;大部分都遵守冯诺依曼体系。 截至目前&#xff0c;我们所认识的计算机&#xff0c;都是有一个个的硬件组件组成&#xff0c; 输入单元&#xff1a;包括键盘 , 鼠…

选GB28181还是RTSP?

好多开发者&#xff0c;搞不清楚什么时候用GB28181&#xff0c;什么时候用RTSP&#xff0c;本文就二者使用场景和区别&#xff0c;做个大概的探讨&#xff1a; 定义与性质&#xff1a; GB28181&#xff1a;是中国国家标准&#xff0c;全称为《公共安全视频监控联网系统信息传输…

安科瑞诚邀您参加2024新加坡亚洲数据中心展

Exhibition Time: October 09-10, 2024 展览时间&#xff1a;2024年10月09日-10日 Exhibition Hall: Sands Expo & Convention Center 展览馆&#xff1a;Sands Expo & Convention Center Exhibition Number: BASEMENT2-L16 展览号&#xff1a;BASEMENT2-L16 Add…

文献阅读(222) VVQ协议死锁

题目&#xff1a;VVQ: Virtualizing Virtual Channel for Cost-Efficient Protocol Deadlock Avoidance时间&#xff1a;2023会议&#xff1a;HPCA研究机构&#xff1a;KAIST request-reply协议死锁如下图所示&#xff0c;每个node收到request之后发送reply&#xff0c;但是想…

2020-11-06《04丨人工智能时代,新的职业机会在哪里?》

《香帅中国财富报告25讲》 04丨人工智能时代&#xff0c;新的职业机会在哪里&#xff1f; 1、新机会的三个诞生方向 前两讲我们都在说&#xff0c;人工智能的出现会极大地冲击现有的职业&#xff0c;从2020年开始&#xff0c;未来一二十年&#xff0c;可能有一半以上的职业都会…

人工智能与生活:探索科技未来的无限可能性

随着科技的不断进步&#xff0c;人工智能已经成为了我们日常生活中不可或缺的一部分。从智能手机到智能家居&#xff0c;从自动驾驶汽车到医疗诊断&#xff0c;人工智能已经渗透到了我们的方方面面。在这篇文章中&#xff0c;我们将从不同的角度探讨人工智能与生活的联系&#…

A股异动与IP数据地址关联分析

最近A股经历了一些显著的移动。在2024年10月9号&#xff0c;A股三大指数大幅下跌&#xff0c;沪指、深成指、和创业板指分别下跌6.62%、8.15%和10.59%。市场的复杂性和不确定性明显&#xff0c;也由此给我们提供了从IP数据地址角度进行分析的机会。 从市场的基本面来看&#xf…

windows10系统-设置账户密码有效期

操作系统: windows10 .a.打开windows10用户管理界面 windows R -> 输入 gpedit.msc ->确定 如下图所示; .b.点击Windows设置->安全设置->账户策略->密码策略 .c.选中密码最长有效期限&#xff0c;修改即可。 修改后示例如下 关于第一条&#xff1a;密码必须符…

Jmeter脚本录制、Badboy脚本录制

目录 Jmeter脚本录制 Badboy脚本录制 Jmeter脚本录制 1、首先添加一个http测试脚本记录器 2、选择目标控制器&#xff0c;把录制的内容放到的地方 3、分组&#xff0c;就是在录制的时候&#xff0c;每一步操作之间间隔方式&#xff0c;根据自己需要进行选择 4、开启浏览…

网站服务器监控:Lighttpd指标解读

监控易是一款功能强大的IT监控软件&#xff0c;它提供了全面的应用和业务监控解决方案&#xff0c;帮助用户实时监控各类IT资源和应用的状态&#xff0c;确保业务的连续性和稳定性。在网站服务器监控方面&#xff0c;监控易特别针对Lighttpd服务器进行了深入的监测&#xff0c;…

专利开放许可与知识产权保护的关系是什么?

专利开放许可在一定程度上是对知识产权保护制度的补充和拓展。知识产权保护的核心目标是鼓励创新&#xff0c;通过赋予专利所有者一定期限内的独占权&#xff0c;使其能够从创新成果中获得经济回报&#xff0c;从而激励更多的创新投入。 专利开放许可则为专利的应用和传播提供了…

C++17中的常用文件操作std::filesystem::directory_iterator【注意事项】

目录 疑问 代码 结果 疑问 怎么用呢&#xff1f;constauto& entry : std::filesystem::directory_iterator(mainFolderPath)中&#xff0c;entry 表示的是什么呢&#xff1f;是mainFolderPath里的文件夹名字吗&#xff1f;还是路径呢&#xff1f;【答案是路径】。我们打…

12 项 ECMAScript 提案的最新进展!

大家好&#xff0c;我是 ConardLi。 近日&#xff0c;ECMA 国际技术委员会 39&#xff08;TC39&#xff09;在东京召开了第 104 次大会&#xff0c;讨论了多项 ECMAScript&#xff08;JavaScript&#xff09;提案的进展情况&#xff0c;批准了其中多项提案进入下一个阶段。 「…

优选算法第一讲:双指针模块

优选算法第一讲&#xff1a;双指针模块 1.移动零2.复写零3.快乐数4.盛最多水的容器5.有效三角形的个数6.查找总价格为目标值的两个商品7.三数之和8.四数之和 1.移动零 链接: 移动零 下面是一个画图&#xff0c;其中&#xff0c;绿色部分标出的是重点&#xff1a; 代码实现&am…

技术速递|VS Code Java 9月更新 - 大量 Spring 更新!Gradle 功能优化

作者&#xff1a;Nick Zhu 排版&#xff1a;Alan Wang 大家好&#xff0c;欢迎来到 Visual Studio Code for Java 的九月更新&#xff01;在本篇博客中&#xff0c;我们将介绍一些重要的 Spring 功能更新和 Gradle 增强功能&#xff0c;让我们开始吧&#xff01; Spring 更新 …

深入理解Java并发读写锁——ReentrantReadWriteLock

ReentrantReadWriteLock使用场景 ReentrantReadWriteLock 是 Java 的一种读写锁&#xff0c;它允许多个读线程同时访问&#xff0c;但只允许一个写线程访问&#xff08;会阻塞所有的读写线程&#xff09;。这种锁的设计可以提高性能&#xff0c;特别是在读操作的数量远远超过写…

CDGA|数据治理对企业来说到底有什么用?真的值得做吗?

在当今数字化时代&#xff0c;数据已成为企业运营和决策的核心资源。随着企业规模的扩大和业务复杂性的增加&#xff0c;如何有效管理和利用数据成为了企业面临的重大挑战。数据治理作为一套系统性的方法&#xff0c;旨在确保数据的质量、安全性、合规性和有效性&#xff0c;对…

24软考信息系统监理师考前冲刺20问!你能答上来多少?

距离下半年软考考试还剩不到一个月&#xff01;在此提醒各位考生不要只知道盲目啃书&#xff01;由于今年的软考知识点繁杂&#xff0c;很难抓住重心&#xff01; 这里给大家准备了信息系统监理师考前冲刺20问&#xff0c;帮助各位更好的理解重要考点~供考生备考使用&#xff0…

ROS-melodic moveit

1.安装ROS-melodic 搜索“鱼香ROS”&#xff0c;一键安装&#xff0c;十分方便&#xff0c;感谢大佬做出的贡献。 https://fishros.com/ 2.安装moveit sudo apt-get install ros-melodic-moveit source /opt/ros/melodic/setup.bash3.下载源码 这里用的是胡春旭老师的源码&…

AI网关在应用集成中起到什么作用?

现在&#xff0c;国内外几乎每个SaaS服务商都找到办法把大型语言模型&#xff08;LLM&#xff09;集成到自己的产品里。印证了那句话“每款SaaS都值得用AI重做一遍”我们暂且不讨论是否值得用AI重做&#xff0c;但是增加AI的功能&#xff0c;确实能让产品有更多的卖点。 通过整…