Linux:深入了解fd文件描述符
目录
1. 文件分类
2. IO函数
2.1 fopen读写模式
2.2 重定向
2.3 标准文件流
3. 系统调用
3.1 open函数认识
3.2 open函数使用
3.3 close函数
3.4 write函数
3.5 read函数
4. fd文件描述符
4.1 标准输入输出
4.2 什么是文件描述符
4.3 语言级文件操作
1. 文件分类
文件=文件内容+文件属性
因此,一个文件里面没有写入内容,也是占据空间的。
在C语言中,我们访问一个文件之前,都必须先调用fopen接口打开文件,这是为什么呢?下面是一份访问文件操作的C语言代码。
#include <stdio.h>int main()
{FILE* fp = fopen("log.txt", "w");if (fp == NULL){perror("fopen");return 1;}const char *message = "hello file\n";int i = 0;while(i < 4){fputs(message, fp);i++;}fclose(fp);return 0;
}
当执行可执行程序时,会在当前目录下创建一个log.txt文件,并往log.txt文件写入几行文字。但是这并不意味着文件在代码编写完毕或编译成可执行程序时已经打开。实际上,文件时在程序运行并且执行到fopen函数调用时,如果调用成功,文件才会被打开。所以是谁在访问文件?本质上是进程在访问。
进程是运行程序的实例,保存在内存当中。在文件没打开之前,它是存储在磁盘中。程序的执行本质上是给CPU执行程序里的代码并进行操作。根据冯诺依曼体系结构,CPU不能直接访问外设数据,它只能访问并处理内存数据。因此,为了实现对文件的读写操作,进程需要将文件从磁盘中加载到内存当中,这个过程被称之为打开文件。
文件从磁盘中加载到内存中,加载的通常是文件的内容或属性。一个进程可以同时打开多个文件,那么多个进程打开的文件数量可能会有上百个。这么多的文件在内存当中肯定也要被管理起来。如何管理文件?先描述,在组织。 在内核中,文件=文件内核数据结构+文件内容。
而进程也有自己的内核数据结构task_struct。所以研究打开的文件,是在研究进程和文件的关系,可以转换成进程内核数据结构和文件内核数据结构的关系。
2. IO函数
2.1 fopen读写模式
fopen函数的第二个参数,是决定文件打开后读写的方式。 带上+号表示即可读也可写。
#include <stdio.h>int main()
{FILE* fp = fopen("log.txt", "w");if (fp == NULL){perror("fopen");return 1;}const char *message = "hello world\n";int i = 0;while(i < 4){fputs(message, fp);i++;}fclose(fp);return 0;}
上面的代码中,fopen函数读写方式是“w”,它会将文件内容长度截断为零,或者创建不存在的文件,再进行写入。log.txt文件原本文本内容是“hello file”,运行filecode程序之后,变成了“hello world”。
#include <stdio.h>int main()
{FILE* fp = fopen("log.txt", "w");if (fp == NULL){perror("fopen");return 1;}fclose(fp);return 0;}
上面的代码使用“w”模式打开文件后,什么都不做。原本log.txt文件内部有四行文本,运行该程序后,什么都没打印出来,说明已经被清空。
#include <stdio.h>int main()
{FILE* fp = fopen("log.txt", "a");if (fp == NULL){perror("fopen");return 1;}const char *message = "hello file\n";int i = 0;while(i < 4){fputs(message, fp);i++;}fclose(fp);return 0;}
fopen函数的第二个参数传入“a”,表示再原有的文件内容末尾追加信息。如下面所示。
2.2 重定向
Linux中,也有类似fopen的“w”模式下的操作。如echo命令后面加上字符串,默认是打印在显示屏上的,如果加上“>”符号并在后面跟上文件名,就会将该文件内容先清空,再写入字符串。
如果你只想清空文件内容,可以直接再命令行上输入">"符号并加上文件名。
如果想做到在文件末尾追加内容,可以使用“>>”符号,类似fopen的append模式。
2.3 标准文件流
任何一个程序启动时,会打开三个标准文件流。C语言中有三个标准输入输出文件流,分别是:
- stdin,标准输入,对应的是键盘,从键盘获取。
- stdout,标准输出,对应的是显示器,输出到显示器。
- stderr,标准错误,对应的是显示器,输出到显示器。
标准文件流的数据类型就是C语言标准库提供的文件流指针FILE*,C语言对键盘和显示器进行包装,成为三个文件流,之后我们对键盘和显示器就可以通过文件指针的形式进行访问。
实际上,其实是进程会打开这个三个标准输入输出流。C++中的标准文件流是cin、cout、cerr。java也会有对应的标准输入输出。其他任何编程语言都会带有标准输入输出,所有语言都具有的性质,那么就要上升到系统的高度来看待这个问题。
那么我们有几种方法打印文本到显示器上?
#include <stdio.h>int main()
{printf("printf\n");fputs("fputs\n", stdout);fwrite("fwrite\n", 1, 7, stdout);fprintf(stdout, "fprintf\n");return 0;
}
3. 系统调用
我们使用C语言提供的标准库,会对键盘,显示器和磁盘进行访问,访问的对象都是硬件。操作系统作为硬件和软件的管理者,不会允许用户直接访问硬件。所以,C语言文件操作接口函数,不可能直接越过操作系统直接访问硬件,底层一定要封装对应的文件类系统调用。
3.1 open函数认识
open函数就是fopen函数封装的系统调用接口。第一个参数是文件的路径。
第二个参数是一个标记位。上面五个是常见的选项,都是宏。O_RDONLY表示只读,O_WRONLY表示只写。O_RDWR表示可读可写。O_APPEND表示追加。O_CREAT表示传入路径文件不存在,新建该文件。
flags是一个整型变量,一般有32个比特位,每个比特位0和1就能代表某个选项的存在,所以说flags实际上是一个32比特位的位图。上面的选项是只有一个比特位为1的值。
那怎么实现的呢,下面有代码实例。
#include <stdio.h>#define ONE (1 << 0) // 00001
#define TWO (1 << 1) // 00010
#define THREE (1 << 2) // 00100
#define FOUR (1 << 3) // 01000
#define FIVE (1 << 4) // 10000void Test(int flags)
{if (flags & ONE){printf("one\n");}if (flags & TWO){printf("two\n");}if (flags & THREE){printf("three\n");}if (flags & FOUR){printf("four\n");}if (flags & FIVE){printf("five\n");}
}int main()
{printf("-----------------------------\n");Test(ONE);printf("-----------------------------\n");Test(TWO);printf("-----------------------------\n");Test(ONE | THREE);printf("-----------------------------\n");Test(FIVE | TWO | ONE);printf("-----------------------------\n");Test(ONE | TWO |THREE | FOUR);printf("-----------------------------\n");return 0;
}
首先需要定义几个宏值,使用左移符号,可以获得只有特定比特位为1的值。Test函数通过按位与实现判断。main函数中,如果想打印多个值,可以将宏选项通过按位或组合起来。
3.2 open函数使用
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>int main()
{open("log.txt", O_WRONLY | O_CREAT);return 0;
}
使用open函数暂时不考虑返回值,使用O_WRONLY和O_CREAT选项的组合,会发现创建出来的文件权限是乱码。
int main()
{open("log.txt", O_WRONLY | O_CREAT, 0666);return 0;
}
如果打开的文件不存在,需要传入第三个参数设置文件读写权限,一般都是0666。如果打开的文件已经存在,可以不传第三个参数。我们设置文件为所有人可读可写,但是其他人只能读。因为系统存在umask掩码,该进程会使用系统的umask掩码,最终权限跟umask有关。
int main()
{umask(0);open("log.txt", O_WRONLY | O_CREAT, 0666);return 0;
}
我们可以使用umask函数设置自己的umask值。如果设置成0,新建文件的权限就是open函数第三个参数。需要注意,进程内部修改umask值,不会影响系统外的umask值。
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>int main(int argc, char *argv[])
{open(argv[1], O_WRONLY | O_CREAT, 0666);return 0;
}
此时,我们可以自己实现一个touch指令,touch指令用来创建新文件,新文件权限664。使用命令行参数表,将第二个命令行参数当做文件名,默认传入权限0666。
open函数的返回值是一个整数。我们随便打开一个文件,返回值是3。该返回值叫做文件描述符,用来表示打开的文件。
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>int main()
{int fd1 = open("log.txt", O_WRONLY | O_CREAT, 0666);if(fd1 < 0){perror("open");return 1;}printf("fd1: %d\n", fd1);return 0;
}
3.3 close函数
close函数用来关闭打开文件的文件描述符。
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>int main()
{int fd1 = open("log.txt", O_WRONLY | O_CREAT, 0666);if(fd1 < 0){perror("open");return 1;}close(fd1);return 0;
}
3.4 write函数
write函数可以向打开的文件进行写入。第一参数是打开文件的文件描述符,第二个参数是指向写入内容的指针变量,第三个参数是写入内容的大小。
write函数的参数跟C语言的文件操作函数非常类似。
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>int main()
{int fd1 = open("log.txt", O_WRONLY | O_CREAT, 0666);if(fd1 < 0){perror("open");return 1;}const char *message = "helloworld\n";write(fd1, message, strlen(message));close(fd1);return 0;
}
但是调用write写入之前是清空文件,还是追加,或者覆盖,要看open函数传入的标记。当我们把上面代码中的字符指针变量内容改为“xxxxx”时,执行该程序,会发现log.txt文件里只是覆盖了helloworld前面的字符。
const char *message = "xxxxx";
添加O_TRUNC到open函数的第二个参数中,Truncate表示截断,向文件写入前会先清空文件内容。
int fd1 = open("log.txt", O_WRONLY | O_CREAT | O_TRUNC, 0666);
如果添加O_APPEND选项,就会在文件末尾追加写入内容。
int fd1 = open("log.txt", O_WRONLY | O_CREAT | O_APPEND, 0666);const char *message = "xxxxx";
3.5 read函数
read函数可以读取打开的文件内容。第一参数是打开文件的文件描述符,第二个参数是指针变量,
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>int main()
{int fd1 = open("log.txt", O_RDONLY, 0666);char buffer[128];ssize_t s = read(fd1, buffer, sizeof(buffer));if(s > 0){buffer[s] = 0;printf("%s", buffer);}return 0;
}
4. fd文件描述符
4.1 标准输入输出
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>int main()
{int fd1 = open("log.txt1", O_WRONLY | O_CREAT, 0666);int fd2 = open("log.txt2", O_WRONLY | O_CREAT, 0666);int fd3 = open("log.txt3", O_WRONLY | O_CREAT, 0666);int fd4 = open("log.txt4", O_WRONLY | O_CREAT, 0666);printf("fd1: %d\n", fd1);printf("fd1: %d\n", fd2);printf("fd1: %d\n", fd3);printf("fd1: %d\n", fd4);return 0;
}
当我们使用open函数打开四个文件,它们的文件描述符从3开始,依次递增。为什么新建的文件描述符会从3开始呢?
因为进程启动时,默认打开三个标准输入输流。文件描述符0,1,2分别被stdin标准输入,stdout标准输出,stderr标准错误占据。那怎么证明呢?可以使用write函数,对文件描述符1里写入。
#include <stdio.h>
#include <unistd.h>
#include <string.h>int main()
{const char *message = "hello stdout\n";write(1, message, strlen(message));return 0;
}
还可以读取键盘输入内容,使用read函数,填上0文件描述符。启动程序,界面会卡在那里,等待键盘输入。
int main()
{char buffer[128];ssize_t s = read(0, buffer, sizeof(buffer));if(s > 0){buffer[s] = 0;printf("%s", buffer);}return 0;
}
4.2 什么是文件描述符
根据上面的讲解,我们知道文件描述符是个整数,并且从0开始,不断递增。碰巧的是数组下标也是从0开始的整数,不断递增。那么文件描述符和数组下标有什么关系呢?
- 一个程序启动,被加载到内存中,操作系统会分配给一个task_struct结构体对象。如果有多个进程,那么操作系统会使用一张链表管理所有的进程的task_struct对象,这是进程管理。
- 当CPU执行到open函数,打开log.txt文件,那么需要将磁盘上的文件加载到内存中。为了方便管理,操作系统会创建一个名为file的结构体对象给该文件,file结构体里面包含许多属性,一部分来自磁盘上文件的属性,还有一部分是操作系统所赋予的。
- 进程启动时,默认打开三个标准输入输出流,对应键盘和显示器。操作系统也会给它们创建file结构体对象。当进程打开的文件变多了,内存中就存在许多file结构体对象。此时,操作系统也会使用一张链表,来管理所有的file结构体对象,这就是文件管理。
- 而进程管理和文件管理必须是松耦合的,如果直接使用一个数据结构统一链接,将难以管理。
- 可进程与文件的关系通常是一对多,一个进程可以打开多个文件。进程要与文件产生关联,只需要加些字段到task_struct结构体中。
- task_struct结构体中有struct file_struct结构体指针对象,file_struct结构体中有个重要的对象,即fd_array数组。它是一个指针数组,存储的是struct file结构体指针,N的大小通常是32或者是64。
- 当进程启动时,自动将fd_array数组前三位填入标准输入输出的file结构体对象地址。如果进程打开其他文件,填充该文件的file结构体对象地址到fd_array数组中空余的位置,然后再返回对应的下标。这就是为什么使用open函数打开的文件,得到的文件描述符从3开始。
- fd_array也叫做文件描述符表,它构建了进程和文件之间的联系。
- 所以文件描述符就是fd_array函数对应的下标。当进程使用某个文件描述符进行操作,会到fd_array数组中对应下标位置中的file结构体地址,找到该文件的file结构体对象。
4.3 语言级文件操作
通过上面的认识,进程对文件的操作,是通过文件描述符进行关联的。那么语言级的文件操作肯定是通过封装系统级文件操作来实现的。
C语言也提供了许多文件操作,如fopen,fwrite,fget等函数。它们的返回值类型都是FILE*,FILE也是个结构体类型,它内部会有许多字段,其中必定有文件描述符的字段。
我们可以通过打印其内部_fileno变量获取文件的文件描述符。
#include <stdio.h>
#include <string.h>int main()
{printf("stdin: %d\n", stdin->_fileno);printf("stdout: %d\n", stdout->_fileno);printf("stderr: %d\n", stderr->_fileno);FILE* fp = fopen("log.txt". "w");printf("fp: %d\n", fp->_fileno);return 0;
}
C语言的文件操作进行了两层封装,第一层是类型的封装,使用FILE封装文件描述符,第二层是接口函数的封装,fopen函数封装了系统调用级open函数。
不管是什么语言,如果要进行文件操作,它的文件类型里面必定包含文件描述符,并对系统调用函数进行封装。
创作充满挑战,但若我的文章能为你带来一丝启发或帮助,那便是我最大的荣幸。如果你喜欢这篇文章,请不吝点赞、评论和分享,你的支持是我继续创作的最大动力!
相关文章:

Linux:深入了解fd文件描述符
目录 1. 文件分类 2. IO函数 2.1 fopen读写模式 2.2 重定向 2.3 标准文件流 3. 系统调用 3.1 open函数认识 3.2 open函数使用 3.3 close函数 3.4 write函数 3.5 read函数 4. fd文件描述符 4.1 标准输入输出 4.2 什么是文件描述符 4.3 语言级文件操作 1. 文件分类…...

springboot 集成 etcd
springboot 集成 etcd 往期内容 ETCD 简介docker部署ETCD 前言 好久不见各位小伙伴们,上两期内容中,我们对于分布式kv存储中间件有了简单的认识,完成了docker-compose 部署etcd集群以及可视化工具 etcd Keeper,既然有了认识&a…...

03_Redis基本操作
1.Redis查询命令 1.1 官网命查询命令 为了便于学习Redis,官方将其用于操作不同数据类型的命令进行了分类整理。你可以通过访问Redis官方网站上的命令参考页面https://redis.io/commands来查阅这些分组的命令,这有助于更系统地理解和使用Redis的各项功能。 1.2 HELP查询命令…...

pycharm-pyspark 环境安装
1、环境准备:java、scala、pyspark、python-anaconda、pycharm vi ~/.bash_profile export SCALA_HOME/Users/xunyongsun/Documents/scala-2.13.0 export PATH P A T H : PATH: PATH:SCALA_HOME/bin export SPARK_HOME/Users/xunyongsun/Documents/spark-3.5.4-bin…...

Unity + Firebase + GoogleSignIn 导入问题
我目前使用 Unity版本:2021.3.33f1 JDK版本为:1.8 Gradle 版本为:6.1.1 Firebase 版本: 9.6.0 Google Sign In 版本为: 1.0.1 问题1 :手机点击登录报错 apk转化成zip,解压,看到/lib/armeabi-v…...

web-app uniapp监测屏幕大小的变化对数组一行展示数据作相应处理
web-app uniapp监测屏幕大小的变化对数组一行展示数据作相应处理 1.uni.getSystemInfoSync().screenWidth; 获取屏幕宽度 2.uni.onWindowResize() 实时监测屏幕宽度变化 3.根据宽度的大小拿到每行要展示的数量itemsPerRow 4.为了确保样式能够根据 items…...

2025年VGC大众汽车科技社招入职测评综合能力英语口语SHL历年真题汇总、考情分析
早在1978年,大众汽车集团就开始了与中国的联系。1984年,集团在华的第一家合资企业—上汽大众汽车有限公司奠基成立;1991年,一汽-大众汽车有限公司成立;2017年,大众汽车(安徽)有限公司…...

Linux中配置Java环境变量
基本工作 1.官网下载java 1.8地址(需要注册一个oracle账户): Java Downloads | Oracle 点击上面的链接,滚动页面到最下面就可以看到下载界面,如下图 选择适合自己系统的版本。 本文选用 jdk-8u431-linux-x64.tar.g…...

完全自定义Qt翻译功能,不使用Qt Linguist的.ts 和 .qm类型翻译
这篇文章展示了集成Qt Linguist 的功能。 但是有时候Qt的翻译功能比较繁琐,我们简单项目只需要使用本地化功能,将中文字符串导入到项目中,避免编码格式问题导致的乱码。 只需要使用一个简单的json或者其他格式的本地文件作为映射的key/value.…...

551 灌溉
常规解法: #include<bits/stdc.h> using namespace std; int n,m,k,t; const int N105; bool a[N][N],b[N][N]; int cnt; //设置滚动数组来存贮当前和下一状态的条件 //处理传播扩散问题非常有效int main() {cin>>n>>m>>t;for(int i1;i&l…...

php函数性能优化中应注意哪些问题
PHP 函数性能优化中的注意事项 在 PHP 应用中优化函数性能对于提升整体运行效率至关重要。以下是一些需要注意的关键问题: 1. 避免内联变量 将变量内联到函数调用中会增加不必要的开销。例如: function sum($a, $b) {return $a $b; }// 不要这样做&…...

安科瑞 Acrel-1000DP 分布式光伏监控系统在工业厂房分布式光伏发电项目中的应用
吕梦怡 18706162527 摘 要:常规能源以煤、石油、天然气为主,不仅资源有限,而且会造成严重的大气污染,开发清洁的可再生能源已经成为当今发展的重要任务,“节能优先,效率为本”的分布式发电能源符合社会发…...
鼠标自动移动防止锁屏的办公神器 —— 定时执行专家
目录 ◆ 如何设置 ◇ 方法1:使用【执行Nircmd命令】任务 ◇ 方法2:使用【模拟键盘输入】任务 ◆ 定时执行专家介绍 ◆ 定时执行专家最新版下载 ◆ 如何设置 ◇ 方法1:使用【执行Nircmd命令】任务 1、点击工具栏第一个图标【新建任务】&…...

各种特种无人机快速发展,无人机反制技术面临挑战
随着科技的飞速发展,各种特种无人机在军事、民用等领域得到了广泛应用,其性能不断提升,应用场景也日益丰富。然而,无人机反制技术的发展确实面临一定的挑战,难以完全跟上无人机技术的快速发展步伐。以下是对这一问题的…...

深入学习RabbitMQ的Direct Exchange(直连交换机)
RabbitMQ作为一种高性能的消息中间件,在分布式系统中扮演着重要角色。它提供了多种消息传递模式,其中Direct Exchange(直连交换机)是最基础且常用的一种。本文将深入介绍Direct Exchange的原理、应用场景、配置方法以及实践案例&a…...

HTML实战课堂之启动动画弹窗
一:代码片段讲解 小提示:下面是一个包含启动页和弹窗的完整示例。这个示例包括一个简单的启动页和一个弹窗,当用户点击启动页上的按钮时,会显示弹窗。 1. **HTML结构**: - #startPage:启动页,包…...

将本地的 Git 仓库上传到 GitHub 上(github没有该仓库)
文章目录 步骤 1:在 GitHub 上创建新仓库步骤 2:配置本地仓库步骤 3:添加远程仓库地址步骤 4:推送本地代码到 GitHub验证上传 步骤 1:在 GitHub 上创建新仓库 登录 GitHub: 打开浏览器并访问 GitHub。使用自…...

【Linux】模拟Shell命令行解释器
一、知识补充 1.1 snprintf snprintf() 是 C语言的一个标准库函数,定义在<stdio.h>头文件中。 snprintf() 函数的功能是格式化字符串,并将结果存储在指定的字符数组中。该函数的原型如下: int snprintf(char *str, size_t size, con…...

G-Star Landscape 2.0 重磅发布,助力开源生态再升级
近日,备受行业瞩目的 G-Star Landscape 迎来了其 2.0 版本的发布,这一成果标志着 GitCode 在开源生态建设方面又取得了重要进展。 G-Star Landscape仓库链接: https://gitcode.com/GitCode-official-team/G-Star-landscape 2024 GitCode 开…...

Lianwei 安全周报|2024.1.7
以下是本周「Lianwei周报」,我们总结推荐了本周的政策/标准/指南最新动态、热点资讯和安全事件,保证大家不错过本周的每一个重点! 政策/标准/指南最新动态 01 国家发改委等三部门印发《国家数据基础设施建设指引》 国家数据基础设施是从数据…...

ASP.NET Core 实现微服务 - Consul 配置中心
这一次我们继续介绍微服务相关组件配置中心的使用方法。本来打算介绍下携程开源的重型配置中心框架 apollo 但是体系实在是太过于庞大,还是让我爱不起来。因为前面我们已经介绍了使用Consul 做为服务注册发现的组件 ,那么干脆继续使用 Consul 来作为配置…...

使用redis的5种常用场景
文章目录 1. 缓存热点数据2. 分布式锁3. 计数器和限流器4. 消息队列5. 会话管理总结 在日常开发工作中,Redis作为一款高性能的内存数据库,凭借其强大的功能特性和卓越的性能表现,已经成为了许多项目中不可或缺的组件。本文将详细介绍Redis在实…...

微信小程序防止重复点击事件
直接写在app.wpy里面,全局可以调用 // 防止重复点击事件preventActive(fn) {const self this;if (this.globalData.PageActive) {this.globalData.PageActive false;if (fn) fn();setTimeout(() > {self.globalData.PageActive true;}, 3000); //设置该时间内…...

PySpark用sort-merge join解决数据倾斜的完整案例
假设有两个大表 table1 和 table2 ,并通过 sort-merge join 来解决可能的数据倾斜问题。 from pyspark.sql import SparkSession from pyspark.sql.functions import col# 初始化SparkSession spark SparkSession.builder.appName("SortMergeJoinExample&quo…...

sklearn-逻辑回归-制作评分卡
目录 数据集处理 分箱 分多少个箱子合适 分箱要达成什么样的效果 对一个特征进行分箱的步骤 分箱的实现 封装计算 WOE 值和 IV值函数 画IV曲线,判断最佳分箱数量 结论 pd.qcut 执行报错 功能函数封装 判断分箱个数 在银行借贷场景中,评分卡是…...

scrapy爬取图片
scrapy 爬取图片 环境准备 python3.10scrapy pillowpycharm 简要介绍scrapy Scrapy 是一个开源的 Python 爬虫框架,专为爬取网页数据和进行 Web 抓取而设计。它的主要特点包括: 高效的抓取性能:Scrapy 采用了异步机制,能够高效…...

在 Vue 项目中使用地区级联选
在 Vue 项目中使用地区级联选择的完整流程: 1.安装依赖包,这个包提供了中国省市区的完整数据。 npm install element-china-area-data --save 2.导入数据 import { regionData } from element-china-area-data 这个包提供了几种不同的数据格式&#…...

【简博士统计学习方法】第1章:1. 统计学习的定义与分类
自用笔记 1. 统计学习的定义与分类 1.1 统计学习的概念 统计学习(Statistical Machine Learning)是关于计算机基于数据构建概率统计模型并运用模型对数据进行预测与分析的一门学科。 以计算机和网络为平台;以数据为研究对象;以…...

利用 Python 脚本批量创建空白 Markdown 笔记
文章目录 利用 Python 脚本批量创建空白 Markdown 笔记1 背景介绍2 需求描述3 明确思路4 具体实现4.1. 遍历 toc.md 文件,收集文件名和对应的文件内容4.2. 实现文件批量生成逻辑4.3. 补全缺失的工具函数4.4. 进一步补全工具函数中的工具函数 5 脚本运行6 注意事项 利…...

【Qt】C++11 Lambda表达式
1. 举例 connect(ui->pushButton, &QPushButton::clicked, [](bool checked){//具体代码qDebug() << "Hello" << checked;}); 2. 详情 //完整形式 [ capture ] ( params ) opt -> ret { body; }; capture 是捕获列表params 是参数表opt 是函数…...