Linux---文件io

1.系统调用

由操作系统实现并提供给外部应用程序的编程接口。(Application Programming Interface,API)。是应用程序同系统之间数据交互的桥梁。

C标准函数和系统函数调用关系。一个helloworld如何打印到屏幕。

man手册中一共有九卷,其中一卷就有讲到系统调用,内核就当前操作系统的核心程序,系统的本质都是个程序。内核和硬件打交道,提供的函数只能给上层应用所使用。

提供的系统调用函数实际上在linux内核当中是没有的,只不过却有与之对应的一样功能的函数,比如open在内核当中的源码对应的是sys_open,虽然名字不同,但是几乎是一模一样的

sys_open >>浅封装>> open,操作系统避免与用户进行交互,但又不想让用户真正窥探到内核,因此使用了浅封装给内核中的sys_open包了个保护壳变成open函数让用户可以去调用系统而又不会导致让用户窥探到本质

2.open/close

函数原型:

要导入头文件 #include<unistd.h>

int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
int close(int fd);
int creat(const char *pathname, mode_t mode);# 可以通过 man open 2 指令去查看配置的文档# pathname:文件路径# flags:打开方式# mode: 权限,mode_t是一个八进制的整型# 返回的是一个文件描述符,如果执行错误,会返回-1# 同时返回一个errno(操作系统的全局变量),需要导入 errno.h# 返回的errno的数字想要知道是什么含义可以通过 man strerror 去查看

常用参数 -- flags

要导入头文件:#include<fcntl.h>

O_RDONLY

O_WRONLY
O_RDWR读写
O_APPEND追加
O_CREAT创建
O_EXCL存放
O_TRUNC截断
O_NONBLOCK非阻塞

创建文件时,指定文件访问权限。权限同时受umask影响。结论为:

文件权限 = mode & ~umask

使用头文件:<fcntl.h>

O_CREAT -- 如果没有该文件就进行创建

创建文件时,其权限与umask挂钩,比如umask = 0002,取反后就是775,然后与mode进行按位与(二进制),最后才得出创建文件的真正权限

 O_TRUNC --- int ftruncate(int fd, off_t length); -- 把文件截断成0

open常见错误

1. 打开文件不存在

2. 以写方式打开只读文件(打开文件没有对应权限)

3. 以只写方式打开目录

perror、strerror、errno

运用

[....]# cd /linux_01
[....]# mkdir -a ./file_IO_test/test
[....]# cd ./file_IO_test/test
[....]# touch dict.txt
[....]# touch ./makefile
[....]# mkdir ./dirct
[....]# vim open.c#include<unistd.h>#include<stdlib.h>#include<fcntl.h>#include<string.h>int main(int argc,char *agrv[]){int fd = 0;fd = open("./dict.txt",O_RDONLY);printf("fd = %d\n",fd);int fd1 = 0;fd1 = open("./dict.cp",O_RDONLY | O_CREAT,0644);printf("fd1 = %d\n",fd);//1.打开文件不存在int fd2 = 0;fd2 = open("./dict.cp1",O_RDONLY);         printf("fd2 = %d, error = %d:%s\n",fd2,error,strerror(error)));//2.以写方式打开只读文件(打开文件没有对应权限)int fd3 = 0; open("./dict.cp2",O_RDONLY | O_CREAT,0411); //创建一个只读文件fd3 = open("./dict.cp2",O_WRONLY);printf("fd3 = %d, error = %d:%s\n",fd3,error,strerror(error)));//fd = -1,errno=13:Permissiondenied//3.以只写方式打开目录int fd4 = 0;fd4 = open("./dict.cp2",O_WRONLY);printf("fd4 = %d, error = %d:%s\n",fd4,error,strerror(error)));// fd = -1, errno=21:Is a directory                                                   close(fd);......return 0;}

3.read/write函数

ssize_t read(int fd, void *buf, size_t count); 从指定位置fd读,然后将读取的东西存入缓冲区buf(待写出数据的缓冲区),count是数据的大小成功的话会返回读取到的字节数(读取到文件尾部会返回0),失败的话会返回-1,同时设置errno
ssize_t write(int fd, const void *buf, size_t count);

练习:编写程序实现简单的cp功能。
[....]# vim cptest.c#include<Stdio.h>#include<stdlib.h>  //perror所用到的头文件....#include<fcntl.h>int main(int agrc,int **argv){char buf[1024];int n = 0;int fd1 = open(argv[1],O_RDONLY); //readif(fd1 == -1){perror("open argv1 error\n");// 如果读取出错就打印出自定义提示 exit(1);       }int fd2 = open(argv[2],O_RDWR|O_CREAT|O_TRUNC,0644);# fd2是创建打开一个文件进行进行写入操作,如果该文件中有我内容则清0# 如果没有该文件就创建该文件,目的是将fd1的内容写入到fd2if(fd2 == -1){perror("open argv2 error\n");// 如果读取出错就打印出自定义提示 exit(1);       }//写入操作:while((n = read(fd1,buf,1024))!=0){if(n < 0){perror("read error");break;           }write(fd2,buf,n);// 第三个参数为n是为了防止缓冲区资源的浪费        }close(fd1);close(fd2);return 0;}
gcc cptest.c  -o cptest
./cptest.c open.c open2.c
# open.c是要拷贝过去的内容,open2.c是拷贝目的地

比较:如果一个只读一个字节实现文件拷贝,使用read、write效率高,还是使用对应的标库函数(fgetc、fputc)效率高呢?

理想上是write比fputc效率更高:

不管是fputc还是write,最终目的都是要从用户空间进入到系统内核,然后系统内核去驱动磁盘进行写入写出工作,但是只有系统函数才能才去调用系统内核让驱动工作,因此write效率更高,因为write本身就是系统调用提供的函数。而fputc并不是系统调用提供的函数,它底层是先去调用write,然后从用户空间进入到内核空间,借助驱动去驱动磁盘工作

但真是这样吗?

但实际上却是fputc比wirte效率更快:

strace ./可执行文件名称

可以看函数的调用过程

用read和write:read一次读一个,write一次写一个,一次只读取一个字节

用fgetc和fputc:并不是一个字节一个字节的操作,而是4096个字节的进行一次操作

探究:

fputc有自己的缓冲区,当缓冲区的东西满了后,才会去调用write进入到内核,将数据放入到系统级缓冲区,调用驱动进入到磁盘

而write和read没有自己的缓冲区,又因为人为的将buf缓冲区设置为1,因此只能不断地来回反复操作只读取或写入一个字节

----因此可以将buf缓冲区的大小重新设置好,就能实现wirte和read效率更高

read、write函数常常被称为Unbuffered I/O。指的是无用户及缓冲区。但不保证不使用内核缓冲区。-----预读入和缓输出

4.文件描述符

PCB进程控制块

使用命令查看其位置:
[....]# locate sched.h
/usr/src/linux-headers-3.16.0-30/include/linux/sched.hPCB进程控制块就像一个结构体
struct task_struct { 结构体 }

文件描述符

结构体PCB 的成员变量file_struct *file 指向文件描述符表。

从应用程序使用角度,该指针可理解记忆成一个字符指针数组,下标0/1/2/3/4...找到文件结构体。

本质是一个键值对0、1、2...都分别对应具体地址。但键值对使用的特性是自动映射,我们只操作键不直接使用值。

value中就是个指针指向了一个文件结构体,这个文件结构体中记录了进行操作文件的内容,比如属组、属主、路径等,但操作系统不想暴露这些value,因此只返回了key的值 -- 文件描述符

新打开文件返回文件描述符表中未使用的最小文件描述符。

  • STDIN_FILENO  0
  • STDOUT_FILENO  1
  • STDERR_FILENO 2

最大打开文件数:

一个进程默认打开文件的个数1024。

命令:ulimit -a 查看open files 对应值。默认为1024,可以使用ulimit -n 4096 修改;当然也可以通过修改系统配置文件永久修改该值,但是不建议这样操作。

cat /proc/sys/fs/file-max 可以查看该电脑最大可以打开的文件个数。受内存大小影响

FILE结构体

主要包含文件描述符、文件读写位置、IO缓冲区三部分内容。

struct file {...文件的偏移量;文件的访问权限;文件的打开标志;文件内核缓冲区的首地址;struct operations * f_op;...};

查看方法:

(1) /usr/src/linux-headers-3.16.0-30/include/linux/fs.h

(2) lxr:百度 lxr → lxr.oss.org.cn → 选择内核版本(如3.10) → 点击File Search进行搜索

        → 关键字:“include/linux/fs.h” → Ctrl+F 查找 “struct file {”

        → 得到文件内核中结构体定义

        → “struct file_operations”文件内容操作函数指针

        → “struct inode_operations”文件属性操作函数指针

5.阻塞和非阻塞

读常规文件是不会阻塞的,不管读多少字节,read一定会在有限的时间内返回。从终端设备或网络读则不一定,如果从终端输入的数据没有换行符,调用read读终端设备就会阻塞,如果网络上没有接收到数据包,调用read从网络读就会阻塞,至于会阻塞多长时间也是不确定的,如果一直没有数据到达就一直阻塞在那里。同样,写常规文件是不会阻塞的,而向终端设备或网络写则不一定。

现在明确一下阻塞(Block)这个概念。当进程调用一个阻塞的系统函数时,该进程被置于睡眠(Sleep)状态,这时内核调度其它进程运行,直到该进程等待的事件发生了(比如网络上接收到数据包,或者调用sleep指定的睡眠时间到了)它才有可能继续运行。与睡眠状态相对的是运行(Running)状态,在Linux内核中,处于运行状态的进程分为两种情况:

正在被调度执行。CPU处于该进程的上下文环境中,程序计数器(eip)里保存着该进程的指令地址,通用寄存器里保存着该进程运算过程的中间结果,正在执行该进程的指令,正在读写该进程的地址空间。

就绪状态。该进程不需要等待什么事件发生,随时都可以执行,但CPU暂时还在执行另一个进程,所以该进程在一个就绪队列中等待被内核调度。系统中可能同时有多个就绪的进程,那么该调度谁执行呢?内核的调度算法是基于优先级和时间片的,而且会根据每个进程的运行情况动态调整它的优先级和时间片,让每个进程都能比较公平地得到机会执行,同时要兼顾用户体验,不能让和用户交互的进程响应太慢。

  • 阻塞读终端:【block_readtty.c】
  • 非阻塞读终端【nonblock_readtty.c】
  • 非阻塞读终端和等待超时【nonblock_timeout.c】

注意,阻塞与非阻塞是对于文件而言的。而不是read、write等的属性。read终端,默认阻塞读。

总结read 函数返回值:   

  1. 返回非零值:  实际read到的字节数
  2. 返回-1:
    1. errno != EAGAIN (或!= EWOULDBLOCK)  read出错
    2. errno == EAGAIN (或== EWOULDBLOCK)  设置了非阻塞读,并且没有数据到达。read在以非阻塞方式读一个设备文件(网络文件),并且文件无数据
  3. 返回0:读到文件末尾

例子:

/dev/tty -- 终端文件,STDIN_FILENO和STDOUT_FILENO都是终端文件中的内容,实际上终端文件是已经跟着打开的了

标准输入和输出,当运行该文件时,如果不按键盘输入东西和点击回车,这时候终端就在等待,称为阻塞

阻塞是设备文件、网络文件的属性,不要误以为阻塞是read和write的特性,并且读常规文件无阻塞属性

那么能不能用非阻塞的方式去操作终端文件?

用open中的O_NONBLOCK非阻塞的方式打开tty终端文件,这时候只会反复的读,读到了就输出到屏幕,读不到就继续读,终端并不会进入等待状态(阻塞)

6.fcntl函数

【fcntl.c】 想改变文件的访问控制属性,比如从阻塞状态变成非阻塞状态,那就得关闭文件重新打开文件进行操作,而使用 fcntl 函数可以直接改变

改变一个【已经打开】的文件的访问控制属性,重点掌握这两个参数的使用,F_GETEL F_SETFL

F_GETFL 读取到标准输入终端文件的状态后,通过 |= 添加上非阻塞属性,然后用F_SETFL 将其重新设置,使标准输入变为非阻塞

7.lseek函数

理解

官方定义:重新定位读或写的文件偏移量。

Linux中可使用系统函数lseek来修改文件偏移量(读写位置)

  • 每当打开一个文件,都会有一个叫做“当前文件偏移量”的东西,如果难理解也可以将他理解为指针。 除非打开文件时指定O_APPEND选项,否则文件偏移量默认设置为0。当我们发生了一次读或者写操作时,都会使这个当前文件偏移量发生变化,读/写多少字节,当前偏移量就会向后移动多少。
  • 因此当我们对一个新文件进行完写操作后,进行读操作,会发现什么都读不到,是因为偏移量经过写操作后移到了文件尾部,此时进行读操作肯定什么都读不到了,也就是读和写操作用的是同一个偏移量(文件指针)

lseek和标准I/O库的fseek函数类似,可以移动当前读写位置(或者叫偏移量)。

回忆fseek的作用及常用参数:
SEEK_SET、SEEK_CUR、SEEK_END
int fseek(FILE *stream, long offset, int whence); 
成功返回0;失败返回-1
特别的:超出文件末尾位置返回0;往回超出文件头位置,返回-1include<lseek.c>
off_t lseek(int fd, off_t offset, int whence); 参数:fd //文件描述符,可以通过open函数得到,通过这个fd可以操作某个文件参数: offset //文件偏移量,是一个整形数,与whence对应的位置继续往后偏移参数:whence //偏移类型,下列三个值中选一个。SEEK_SET:该文件的偏移量设为离文件开头offset个字节.SEEK_CUR:该文件的偏移量设为其当前值加offset(PS :offest可正负).SEEK_END:该文件的偏移量设为文件长度加offset
特别的:lseek允许超过文件结尾设置偏移量,文件会因此被拓展。注意文件“读”和“写”使用同一偏移位置。                                
lseek函数返回的偏移量(off_t)总是相对于文件头而言的。                                

作用

  1. 移动文件指针到文件头:lseek(fd, 0, SEEK_SET)
  2. 获取当前文件指针的位置:lseek(fd, 0, SEEK_SUR)
  3. 获取文件长度:lseek(fd, 0, SEEK_END)
  4. 拓展文件的长度,当前文件10b、110b,增加了100个字节:lseed(fd, 100, SEEK_END),需要注意拓展完需要再写一次数据,否侧拓展无效

还有另一种方式也可以来拓展文件的大小

[....]# main 2truncate  # 可以查找到另一个函数truncate
>>>int truncate(const char* path, off_t length)

例子

1.移动文件指针到文件头和获取当前文件指针的位置

//导入所有需要的头文件
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<fcntl.h>//我们的目的是:移动文件指针到文件头:
int main()
{//获取文件的文件描述符int fd = open("text.txt", O_RDWR);if (fd == -1){perror("open");return -1;}//输出当前文件的偏移量long long int loc = lseek(fd, 0, SEEK_CUR);printf("%lld\n", loc);   //0//使用read函数读3个字节的数据char buf[3] = {0};int rnum = read(fd, buf, sizeof(buf));printf("%d\n", rnum);   //3//再次查看文件的偏移量(获取当前文件指针的位置)long long int loc1 = lseek(fd, 0, SEEK_CUR);printf("%lld\n", loc1);   //3//移动文件指针到文件头long long int loc2 = lseek(fd, 0, SEEK_SET);printf("%lld\n", loc2);   //0return 0;
}

2.获取文件长度

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<fcntl.h>
int main()
{//获取文件的文件描述符int fd = open("hello.txt", O_RDWR);//获取文件长度long long int loc1 = lseek(fd, 0, SEEK_END);printf("%lld\n", loc1);return 0;
}

3.拓展文件的长度(注:拓展完成后需要再写一次数据,否则拓展无效)

int main()
{//获取文件的文件描述符int fd = open("hello.txt", O_RDWR);//获取文件长度long long int loc1 = lseek(fd, 0, SEEK_END);printf("%lld\n", loc1);//拓展文件的长度,需要引起IO操作后文件的大小才会改变//可以通过 ll 指令查看文件的详细属性long long int loc2 = lseek(fd, 100, SEEK_END);write(fd," ",1);//写入一个空数据//该空数据前的100个字节是文件空洞,这是系统自动帮我们填补的:^@printf("%lld\n", loc2);return 0;
}

od -tcx filename  查看文件的16进制表示形式
od -tcd filename  查看文件的10进制表示形式

8.传入传出参数

传入参数:

1.指针作为函数参数

2.通常有const关键字修饰

3.指针指向有效区域, 在函数内部做读操作

char *strcpy(cnost char *src, char *dst);

传出参数:

1.指针作为函数参数

2.在函数调用之前,指针指向的空间可以无意义,但必须有效(如不能指向未初始化的空间)

3.在函数内部,做写操作

4.函数调用结束后,充当函数返回值

传入传出参数:

1.指针作为函数参数

2.在函数调用之前,指针指向的空间有实际意义

3.在函数内部,先做读操作,后做写操作

4.函数调用结束后,充当函数返回值

char strtok(char str, const char delim, char ** saveptr) 其中第三个参数就是传入传出参数

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/880521.shtml

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

相关文章

连锁店收银系统如何选择?

在新零售背景下&#xff0c;连锁店的收银系统扮演着至关重要的角色。随着科技的不断发展和消费者需求的不断变化&#xff0c;一款功能齐全的收银系统不仅可以提高便利店的运营效率&#xff0c;还可以提供更好的消费体验。以下是连锁店收银系统必备的功能。 1.收银系统能支持独…

【二十七】【QT开发应用】VS如何复制项目,QT无边窗窗口Pro版本,信号与信号槽的应用,背景图片自适应控件大小

VS复制项目 在使用VS的过程中,有的时候我们需要复制我们已经存在的项目. 我们可以先创建一个新的项目. 接着把需要复制的项目的文件复制粘贴到新的项目文件夹中. 不要忘记添加现有项目. CFrameLessWidgetBase.h #pragma once #include <QWidget> class CFrameLessWi…

书生大模型实战(从入门到进阶)L2-茴香豆:企业级知识库问答工具

目录 茴香豆介绍 茴香豆本地标准版搭建 环境搭建 配置服务器&#xff1a; 搭建茴香豆虚拟环境&#xff1a; 安装茴香豆 下载茴香豆 安装茴香豆所需依赖 下载模型文件 更改配置文件 知识库创建 测试知识助手 命令行运行 Gradio UI 界面测试 本文是对书生大模型L2-茴香…

SwiftUI简明概念(3):Path.addArc的clockwise方向问题

一、画个下半圆 SwiftUI中绘制下半圆的一个方法是使用Path.addArc&#xff0c;示例代码如下&#xff1a; var body: some View {Path { path inpath.addArc(center: CGPoint(x: 200, y: 370), radius: 50, startAngle: Angle(degrees: 0), endAngle: Angle(degrees: 180.0), …

自然语言处理实战项目:从基础到实战

自然语言处理实战项目&#xff1a;从基础到实战 自然语言处理&#xff08;Natural Language Processing, NLP&#xff09;是人工智能的重要分支&#xff0c;致力于让计算机能够理解、生成和处理人类语言。NLP 在搜索引擎、智能客服、语音助手等场景中扮演着关键角色。本文将带…

MyBatis-Plus分页查询

在实际开发中&#xff0c;对于大量数据的查询&#xff0c;可以通过分页查询的方式来减少查询量和提高查询效率。在 MyBatis-Plus 中&#xff0c;分页查询可以通过使用 Page 对象和 IService 接口提供的分页方法来实现。MyBatis-Plus 的分页插件 PaginationInnerInterceptor 提供…

基于单片机的水位检测系统仿真

目录 一、主要功能 二、硬件资源 三、程序编程 四、实现现象 一、主要功能 基于STC89C52单片机&#xff0c;DHT11温湿度采集温湿度&#xff0c;滑动变阻器连接ADC0832数模转换器模拟水位传感器检测水位&#xff0c;通过LCD1602显示信息&#xff0c;然后在程序里设置好是否…

【文件增量备份系统】MySQL百万量级数据量分页查询性能优化

&#x1f3af; 导读&#xff1a;本文针对大数据量下的分页查询性能问题进行了深入探讨与优化&#xff0c;最初查询耗时长达12秒&#xff0c;通过避免全表计数及利用缓存保存总数的方式显著提升了浅分页查询速度。面对深分页时依然存在的延迟&#xff0c;采用先查询倒数第N条记录…

时间序列LSTM实现

这个代码参考了时间序列预测模型实战案例(三)(LSTM)(Python)(深度学习)时间序列预测(包括运行代码以及代码讲解)_lstm预测模型-CSDN博客 结合我之前所学的lstm-seq2seq里所学习到的知识对其进行预测 import time import numpy as np import pandas as pd import torch import…

Meta Sapiens 人体AI模型

Meta 一直是开发图像和视频模型的领导者&#xff0c;现在他们又增加了一个新东西&#xff1a;Meta Sapiens。和Homo sapiens一样&#xff0c;这个模型也是关于人类的。它旨在执行与人类相关的任务&#xff0c;例如理解身体姿势、识别身体部位、预测深度&#xff0c;甚至确定皮肤…

算法课习题汇总(3)

循环日程表 设有N个选手进行循环比赛&#xff0c;其中N2M&#xff0c;要求每名选手要与其他N−1名选手都赛一次&#xff0c;每名选手每天比赛一次&#xff0c;循环赛共进行N−1天&#xff0c;要求每天没有选手轮空。 例如4个人进行比赛&#xff1a; 思路&#xff1a; 把表格…

Spring MVC 基本配置步骤 总结

1.简介 本文记录Spring MVC基本项目拉起配置步骤。 2.步骤 在pom.xml中导入依赖&#xff1a; <dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>6.0.6</version><scope>…

通过WebTopo在ARMxy边缘计算网关上实现系统集成

随着工业互联网技术的发展&#xff0c;边缘计算成为了连接物理世界与数字世界的桥梁&#xff0c;其重要性日益凸显。边缘计算网关作为数据采集、处理与传输的核心设备&#xff0c;在智能制造、智慧城市等领域发挥着关键作用。 1. BL340系列概述 BL340系列是基于全志科技T507-…

MATLAB仿真实现图像去噪

摘要 数字图像处理是一门新兴技术&#xff0c;随着计算机硬件的发展&#xff0c;其处理能力的不断增强&#xff0c;数字图像的实时处理已经成为可能。由于数字图像处理的各种算法的出现&#xff0c;图像处理学科在飞速发展的同时逐渐向其他学科交叉渗透。数字图像处理是一种通过…

【目标检测】隐翅虫数据集386张VOC+YOLO

隐翅虫数据集&#xff1a;图片来自网页爬虫&#xff0c;删除重复项后整理标注而成 数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;386 标注…

电子电路的基础知识

电子电路是现代电子技术的基础&#xff0c;由电子元件&#xff08;如电阻、电容、电感、二极管、晶体管等&#xff09;和无线电元件通过一定方式连接而成的电路系统。 以下是对电子电路的详细概述&#xff1a; 一、定义与分类 定义&#xff1a;电子电路是指由电子器件和有关无…

240925-GAN生成对抗网络

GAN生成对抗网络 GAN&#xff0c;顾名思义&#xff0c;gan……咳咳&#xff0c;就是干仗嘛&#xff08;听子豪兄的课讲说这个名字还真的源于中文这个字&#xff09;&#xff0c;对应的就有两方&#xff0c;放在这里就是有两个网络互相对抗互相学习。类比武林高手切磋&#xff…

dev containers plugins for vscode构建虚拟开发环境

0. 需求说明 自用笔记本构建一套开发环境&#xff0c;用docker 虚拟插件 dev containers,实现开发环境的构建&#xff0c;我想构建一套LLMs的环境&#xff0c;由于环境配置太多&#xff0c;不想污染本地环境&#xff0c;所以选择隔离技术 1. 环境准备 vscodedocker 2. 步骤…

韦东山FreeRTOS笔记

介绍 这篇文章是我学习FreeRTOS的笔记 学的是哔哩哔哩韦东山老师的课程 在学习FreeRTOS之前已经学习过江协的标准库和一丢丢的超子说物联网的HAL了。他们讲的都很不错 正在更新&#xff0c; 大家可以在我的Gitee仓库中下载笔记源文件、项目资料等 笔记源文件可以在Notion…

idea.vmoptions 最佳配置

1. 推荐的 idea64.exe.vmoptions 配置&#xff1a; -Xms1024m -Xmx4096m -XX:ReservedCodeCacheSize512m -XX:UseG1GC -XX:SoftRefLRUPolicyMSPerMB50 -XX:CICompilerCount4 -XX:HeapDumpOnOutOfMemoryError -XX:-OmitStackTraceInFastThrow -Dsun.io.useCanonCachesfalse -Dj…