【看表情包学Linux】初识文件描述符 | 虚拟文件系统 (VFS) 初探 | 系统传递标记位 | O_TRUNC | O_APPEND
爆笑教程《看表情包学Linux》👈 猛戳订阅!
💭 写在前面:通过上一章节的讲解,想必大家已对文件系统基本的接口有一个简单的了解,本章我们将继续深入讲解,继续学习系统传递标志位,介绍 O_WRONLY, O_TRUNC, O_APPEND 和 O_RDONLY。之后我们就正是打开文件描述符 fd 的大门了,之前我们所探讨讲解的系统文件操作,都是为了给文件描述符做铺垫的,可见这这一块知识点是相当的重要。话不多说,让我们正式开始本章的学习!
📜 本章目录:
Ⅰ. 系统传递标记位
0x00 引入:O_WRONLY 没有像 w 那样完全覆盖?
0x01 O_TRUNC 截断清空(对标 w)
0x02 O_APPEND 追加(对标 a)
0x03 O_REONLY 读取
Ⅱ. 文件描述符(fd)
0x00 引入:open 参数的返回值
0x01 文件描述符的底层理解
0x02 理解:Linux 下一切皆文件
0x03 初识 VFS(虚拟文件系统)
0x04 回头看问题:fd 的 0,1,2,3...
本篇博客全站热榜排名:未上榜
Ⅰ. 系统传递标记位
0x00 引入:O_WRONLY 没有像 w 那样完全覆盖?
语言在
模式打开文件时,文件内容是会被清空的,但是 O_WRONLY 好像并非如此?
💬 代码演示:当前我们的 log.txt 内有 5 行数据,现在我们执行下面的代码:
int main(void)
{umask(0);// 当我们只有 O_WRONLY 和 O_CREAT 时int fd = open("log.txt", O_WRONLY | O_CREAT, 0666);if (fd < 0) {perror("open"); return 1;}printf("fd: %d\n", fd); // 修改:向文件写入 2 行信息int cnt = 0;const char* str = "666\n"; // 修改:内容改成666(方便辨识)while (cnt < 2) {write(fd, str, strlen(str));cnt++;}close(fd);return 0;
}
🚩 运行结果如下:
❓ 疑点:O_WRONLY 怎么没有像 w 那样完全覆盖???
我们以前在 语言中,w 会覆盖把全部数据覆盖,每次执行代码可都是会清空文件内容的。
而我们的 O_WRONLY 似乎没有全部覆盖,曾经的数据被保留了下来,并没有清空!
其实,没有清空根本就不是读写的问题,而是取决于有没有加 O_TRUNC 选项!
因此,只有 O_WRONLY 和 O_CREAT 选项是不够的:
- 如果想要达到 w 的效果还需要增添 O_TRUNC
- 如果想到达到 a 的效果还需要 O_APPEND
下面我们就来介绍一下这两个选项!
0x01 O_TRUNC 截断清空(对标 w)
在我们打开文件时,如果带上 O_TRUNC 选项,那么它将会清空原始文件。
如果文件存在,并且打开是为了写入,O_TRUNC 会将该文件长度缩短 (truncated) 为 0。
也就是所谓的 截断清空 (Truncate Empty) ,我们默认情况下文件系统调用接口不会清空文件的,
但如果你想清空,就需要给 open() 接口 带上 O_TRUNC 选项:
💬 代码演示:让 open() 达到 fopen 中 "w" 模式的效果
int main(void)
{umask(0);int fd = open("log.txt", O_WRONLY | O_CREAT | O_TRUNC, 0666);if (fd < 0) {perror("open"); return 1;}printf("fd: %d\n", fd); // 向文件写入 2 行信息int cnt = 0;const char* str = "666\n";while (cnt < 2) {write(fd, str, strlen(str));cnt++;}close(fd);return 0;
}
🚩 运行结果如下:
然而 语言的 fopen 函数,只需要浅浅地标上一个 "w" 就能搞定了:
fopen("log.txt", "w");
调一个 w 就以写的方式打开了,不存在会自动创建,并且会完全覆盖原始内容,是如此的简单!
它对应的底层 open 调用,调用接口所传入的选项就是 O_WRONLY, O_CREAT, O_TRUNC。
由此可见, 的 fopen 是多么的好用!open 不仅要传这么多选项,而且属性也要设置:
open("log.txt", O_WRONLY | O_CREAT | O_TRUNC, 0666);
fopen("log.txt", "w");
0x02 O_APPEND 追加(对标 a)
上一章我们复习了 a 模式, 语言中我们以 a 模式打开文件做到追加的效果。
现在我们用 open,追加是不清空原始内容的,所以我们不能加 O_TRUNC,得加 O_APPEND:
int fd = open("log.txt", O_WRONLY | O_CREATE | O_APPEND, 0666);
💬 代码演示:让 open() 达到 fopen 中 "a" 模式的效果
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>int main(void)
{umask(0);int fd = open("log.txt", O_WRONLY | O_CREAT | O_APPEND, 0666);if (fd < 0) {perror("open"); return 1;}printf("fd: %d\n", fd); // 向文件写入 2 行信息int cnt = 0;const char* str = "666\n";while (cnt < 2) {write(fd, str, strlen(str));cnt++;}close(fd);return 0;
}
🚩 运行结果如下:
我们再来对照
语言的 fopen,想做到这样的效果只需要一个 "a" :
open("log.txt", O_WRONLY | O_CREAT | O_APPEND, 0666);
fopen("log.txt", "a");
实际上,系统级别的接口本来就是被文件接口封装的,fopen 是系统级文件接口的底层实现。
我们的 a, w, r... 在底层上实际上就是这些 "O_" 组合而成的,使用系统接口麻烦吗?
当然麻烦!要记这么多东西,当然还是 C 语言用的更爽了,一个字母标明文件模式就行了。
0x03 O_REONLY 读取
如果我们想读取一个文件,那么这个文件肯定是存在的,我们传 O_RDONLY 选项:
int main()
{umask(0);int fd = open("log.txt", O_RDONLY);if (fd < 0) {perror("open");return 1;}printf("fd: %d\n", fd);char buffer[128];ssize_t s = read(fd, buffer, sizeof(buffer) - 1);if (s > 0) {buffer[s] = '\0'; // 最后字符串序列设置为 '\0' printf("%s", buffer);}close(fd); return 0;
}
🚩 运行结果如下:
Ⅱ. 文件描述符(fd)
0x00 引入:open 参数的返回值
int fd = open("log.txt", O_WRONLY | O_CREAT, 0666);
我们使用 open 函数举的例子中,一直是用一个叫做 fd 的变量去接收的。
fopen 中我们习惯使用 fp / pf 接收返回值,那是因为是 fopen 的返回值 FILE* 是文件指针,
file pointer 的缩写即是 fp,所以我们就习惯将这个接收 fopen 返回值的变量取名为 fp / pf。
那为什么接收 open 的返回值的变量要叫 fd 呢?
这个 fd 究竟是何方神圣?我们现在就揭开其神秘面纱,一睹芳容!它就是……
open 如果调用成功会返回一个新的 文件描述符 (file descriptor) ,如果失败会返回 -1 。
:失败 (success)
:成功 (failed)
💬 代码演示:我们现在多打开几个文件,观察 fd 的返回值
int main(void)
{int fd_1 = open("log1.txt", O_WRONLY | O_CREAT, 0666);int fd_2 = open("log2.txt", O_WRONLY | O_CREAT, 0666);int fd_3 = open("log3.txt", O_WRONLY | O_CREAT, 0666);int fd_4 = open("log4.txt", O_WRONLY | O_CREAT, 0666);int fd_5 = open("log5.txt", O_WRONLY | O_CREAT, 0666);printf("fd_1: %d\n", fd_1); printf("fd_2: %d\n", fd_2); printf("fd_3: %d\n", fd_3); printf("fd_4: %d\n", fd_4); printf("fd_5: %d\n", fd_5); close(fd_1);close(fd_2);close(fd_3);close(fd_4);close(fd_5);return 0;
}
🚩 运行结果如下:
我们发现这 open 的 5 个文件的 (返回值) 分别是
,那么问题了来了:
① 为什么从 3 开始,而不是从 0 开始?0, 1, 2 去哪了?
- 0:标准输入(键盘,stdin)
- 1:标准输出(显示器,stdout)
- 2:标准错误(显示器,stderr)
系统接口认的是外设,而
标准库函数认的是:
#include <stdio.h>extern FILE* stdin;
extern FILE* stdout;
extern FILE* stderr;
系统调用接口!那么 stdin, stdout, stderr 和上面的 0,1,2 又有什么关系呢?
想解决这个问题,我们得先说说
:
我们知道,FILE* 是文件指针,那么 是什么呢?它是
库提供的结构体。
只要是结构体,它内部一定封装了多个成员!
虽然 用的是 FILE*,但是系统的底层文件接口只认
,也就是说:
标准库调用的系统接口,对文件操作而言,系统接口只认文件描述符。
" 文件操作的系统接口属于是六亲不认,只认 fd "
因此,
内部必定封装了文件操作符
!
下面我们来验证一下,先验证 0,1,2 就是标准
💬 代码验证:0 是标准输入 (stdin)
int main(void)
{// 验证 0,1,2 就是标准 I/Ochar buffer[1024];ssize_t s = read(0, buffer, sizeof(buffer) - 1);if (s > 0) {buffer[s] = '\0';printf("echo: %s", buffer);}
}
🚩 运行结果如下:
💬 代码验证:stdout 标准写入(1) 和 stderr 错误写入(2) :
int main(void)
{const char* s = "Hello, write something\n";write(1, s, strlen(s)); // 1:向标准输入写入write(2, s, strlen(s)); // 2:向标准错误写入
}
🚩 运行结果如下:
(1 和 2 的区别我们放到后面再讲)
至此,我们证明了 ——
每次我们打开文件虽然打开的是 3,但是可以像 3,4,5,6…… 去写,默认系统就会帮我们打开:
0 (标准输入, stdin) ,1 (标准输出, stdout),2 (错误输出, stderr)
下面我们要做的是,验证一下 0,1,2 和 stdin, stdout 和 stderr 的对应关系。
根据我们目前的分析, 本来就是一个结构体, 因为系统只认
,
所以 语言本身调用的一定是系统结构,这就直接决定了不管怎么封装,底层必须有
!
💬 代码验证:下面我们就来证明 的存在,证明 stdin, stdout 和 stderr 的对应关系
int main(void)
{printf("stdin: %d\n", stdin->_fileno);printf("stdout: %d\n", stdout->_fileno);printf("stderr: %d\n", stderr->_fileno);
}
🚩 运行结果如下:
" 这……就是透过现象看本质!"
函数接口的对应:fopen / fclose / fread / fwrite : open / close / read / write
数据类型的对应:(FILE* → FILE) →
🔺 结论:我们用的 语言接口一定封装了系统调用接口!
② 这个 0, 1, 2, 3, 4, 5……,是不是有点像数组下标?
" 咳咳……不是有点像,它就是数组下标!"
刚才返回 的,用的都是系统接口,是操作系统提供的返回值。
既然操作系统能给你,那说明操作系统内部是有的。
文件描述符的值为什么是 1,2,3,4,5... ?为了理解这个问题,我们需要做大量的铺垫!
0x01 文件描述符的底层理解
💭 逻辑推导:进程:内存文件的关系 → 内存 → 被打开的文件实在内存里面的
一个进程可以打开多个文件,所以在内核中,进程与打开的文件之比为:
所以系统在运行中,有可能会存在大量的被打开的文件 → OS 要对这些被打开的文件进行管理!
OS 如何管理这些被打开的文件呢?还是我们老生常谈的那句话:
先描述,再组织!
所以对我们来说,一个文件被打开不要片面的认为只是对文件内容动动手脚!
它还要 在内核中创建被打开文件的内核数据结构 —— 先描述
struct file {// 包含了你想看到的文件的所有大部分 内容 + 属性struct file* next;struct file* prev;
};
* 注:上面的代码是便于理解的,可不是内核真正的代码,真的可远比这复杂得多!
如果你在内核中打开了多个的文件,那么系统会在内核中为文件创建一个 struct file 结构。
可以通过 next 和 prev 将其前后关联起来(内核的链表结构有它自己的设计,这里我们不关注)。
既然你打开了一个文件,就会创建一个 struct file,那么你打开多个文件,
系统中必然会存在大量的 struct file,并且该结构我们用链表的形式链接起来:
如此一来,对被打开的文件的管理,就转化成为了对链表的增删改查!
"这一幕怎么有些似曾相识?我们之前讲进程好像就是这么讲的!task_struct!"
进程与打开的文件之比为 ,进程能打开这么多文件,那么:
进程如何和打开的文件建立映射关系?打开的文件哪一个属于我的进程呢?
在内核中,task_struct 在自己的数据结构中包含了一个 struct files_struct *files (结构体指针):
struct files_struct *files;
而我们刚才提到的 "数组" 就在这个 file_struct 里面,该数组是在该结构体内部的一个数组。
struct file* fd_array[];
该数组类型为 struct file* 是一个 指针数组,里面存放的都是指向 struct file 的指针!
" 指向 struct file 的指针!是不是恍然大悟?这不就是文件的 stuct file 结构么?没错!"
数组元素映射到各个被打开的文件,直接指向对应的文件结构,若没有指向就设为 NULL。
此时,我们就建立起了 "进程" 和 "文件" 之间映射关系的桥梁。
🔍 看图理解:在内核中实现的映射关系
如此一来,进程想访问某一个文件,只需要知道该文件在这张映射表中的数组下标。
上面这些就是在内核中去实现的映射关系了!这个下标 0,1,2,3,4 就是对应的文件描述符 !
我们调用的 open / read / write / close 接口都需要
:
" 可以理解为买彩票,由于关系复杂就不给大家讲故事了,自行理解"
① 选号:当我们 open 打开一个新的文件时,先创建 struct file,然后在当前的文件描述表中分配一个没有被使用的下标,把 stuct file 结构体的地址填入 struct file* 中,然后通过 open 将对应的 返回给用户,比如 3,此时我们的
变量接收的 open 的返回值就是 3 了。
② 兑奖:后续用户再调用 read, write 这样的接口一定传入了对应的 ,找到了特定进程的 files,在根据对应的
索引到指针数组,通过 sturct file* 中存储的 struct file 结构体地址,找到文件对象,之后就可以对相关的操作了。
🔺 总结:其本质是因为它是一个数组下标,系统中使用指针数组的方式,建立进程和文件之间的关系。将 返回给上层用户,上层用户就可以调用后续接口 (read, write...) 来索引对应的指针数组,找到对应文件,这就是
为什么是 0,1,2... 的原因了!
0x02 理解:Linux 下一切皆文件
我们上面说的 0,1,2 → stdin, stdout, stderr → 键盘, 显示器, 显示器,这些都是硬件啊?
也用你上面讲的 struct file 来标识对应的文件吗?在解答这个问题之前,我们需要讲清楚:
" Linux 下一切皆文件 "
一切皆文件这个话题在之前的章节我们已经提过了,但是当时由于知识点尚未展开,没法讲解。
现在我们到了去讲解这个概念的时侯了,希望大家可以尝试去理解 "Linux 下一切皆文件" 。
在这之前我们先说个题外话,其实
语言也是可以模拟面向对象的!
💬 代码演示:在 中用 struct 模拟面向对象
struct file {// 对象的是属性// 函数指针void *(readp)(struct file* filep, int fd ...);void *(writep)(struct file* filep, int fd...);
};void read(struct file* filep, int fd...) {// 逻辑代码
}void write(struct file* filep, int fd...) {// 代码
}
C++ 本身就是从 C 语言衍生出来的,并不是 "万丈高楼平地起" 的。
是大量工程实战后不断积累的产物,所以 C++ 的面向对象实际上在 C 中也能实现。
我们举个例子:我们在计算机中,有各种硬件:键盘、显示器、磁盘、网卡、其他硬件...
对我们现阶段而言,这些设备我们统一称之为 "外设",下面我们来看图。
🔍 看图理解:注意,下图的 "上层" 是刚才演示的 "映射关系图"
深灰色层:对应的设备和对应的读写方法一定是不一样的。
黑色层:看见的都是 struct file 文件(包含文件属性, 文件方法),OS 内的内存文件系统。
红色箭头:再往上就是进程,如果想指向磁盘,通过
找到对应的 struct file,根据对应的 file 结构调用读写方法,就可以对磁盘进行操作了。如果想指向对应的显示器,通过 fd 找到 struct file……最后调用读写,就可以对显示器操作了…… 以此类推。
虽然指针指向的是差异化的代码,但是在 深灰色层,我们看到的都是 struct file 文件对象!
在这一层我们 以统一的视角看待所有的设备,往上我们就看作 "一切皆文件" !
也就是说:如果想打开一个文件,打开之后把读写方法属性交给 OS,
在内核里给该硬件创建 stuct file,初始化时把对应的函数指针指向具体的设备,
在内核中存在的永远都是 struct file,然后将 struct file 互相之间用链表关联起来。
站在用户的角度看,一个进程看待所有的文件都是以统一的视角看待的,
所以当我们访问一个 file 的时候,这个 file 具体指向底层的哪个文件或设备,
这完全取决于其底层对应的读写方法指向的是什么方法!
这操作是不是感觉很熟悉!?
多态?C++ 中运行时多态用的虚表和虚函数指针,那不就是函数指针么?
"上层使用同一对象,指针指向不同的对象,最终就可以调用不同的方法"
这令人拍手叫绝的操作,你可以理解为:多态的前身
📚 补充:上面画的图,在往上走,就回到了内核的映射关系了:
这里的 struct file 指向的硬件设备是谁,就取决于底层的硬件是怎么设计的了。
通过操作系统层做了一层软件封装,达到了这样的效果。
底层叫硬件,而 具体的硬件读写方法是驱动干的,具体的硬件读写是驱动程序要做的,
OS 只管跟外设要求其提供读写方法,最终 OS 在内核中给它们抽象成 struct file,
把它们都看作文件,然后通过函数指针指向具体的文件对应的设备,就完成了 "一切皆文件" !
0x03 初识 VFS(虚拟文件系统)
上面说的这种设置一套 struct file 来表示文件的内存文件系统的操作,
我们称之为 (virtual file system) ,即 虚拟文件系统 。
虚拟文件系统(VFS)是 Linux 内核中非常有用的一个方面,因为它为文件系统提供了一个通用的接口抽象。VFS 在 SCI 和内核所支持的文件系统之间提供了一个交换层。
0x04 回头看问题:fd 的 0,1,2,3...
至此,我们梳理完了。现在我们再回过头看 fd 的 1,2,3,4... 就能有一个清楚的认识了。
现在我们再我们最开始的问题,想必大家已经做到 "知其然知其所以然" 了!
① 为什么从 3 开始,而不是从 0 开始?0, 1, 2 去哪了?
💡 stdin,stdout,stderr 和 0,1,2 是对应关系,因为 open 时默认就打开了,这也是为什么我们默认打开一个新的文件,fd 是从 3 开始的而不是 0 开始的真正原因!
"突然茅塞顿开,上一章打印出 fd 是 3 的疑惑终于解决了!"
② 0, 1, 2, 3, 4……,是不是有点像数组下标?
💡 不是有点像,它其实上就是数组下标!fd 0,1,2,3,4... 在内核中属于进程和文件的对应关系,是用数组来完成映射的,这些数字就是数组的下标。read, write, close 这些接口都必须用 0,1,2,3,4 来找到底层对应的 struct file 结构,进而访问到底层对应的读写方法 (包括相关的属性,缓冲区等) 。
📌 [ 笔者 ] 王亦优
📃 [ 更新 ] 2023.3.24
❌ [ 勘误 ] /* 暂无 */
📜 [ 声明 ] 由于作者水平有限,本文有错误和不准确之处在所难免,本人也很想知道这些错误,恳望读者批评指正!
📜 参考资料 C++reference[EB/OL]. []. http://www.cplusplus.com/reference/. Microsoft. MSDN(Microsoft Developer Network)[EB/OL]. []. . 百度百科[EB/OL]. []. https://baike.baidu.com/. |
相关文章:

【看表情包学Linux】初识文件描述符 | 虚拟文件系统 (VFS) 初探 | 系统传递标记位 | O_TRUNC | O_APPEND
爆笑教程《看表情包学Linux》👈 猛戳订阅! 💭 写在前面:通过上一章节的讲解,想必大家已对文件系统基本的接口有一个简单的了解,本章我们将继续深入讲解,继续学习系统传递标志位&…...

ssm+vue“魅力”繁峙宣传网站源码和论文
ssmvue“魅力”繁峙宣传网站源码和论文102 开发工具:idea 数据库mysql5.7 数据库链接工具:navcat,小海豚等 技术:ssm 摘 要 随着科学技术的飞速发展,各行各业都在努力与现代先进技术接轨,通过科技手段提高自身…...

Linux系统编程5(线程概念详解)
线程同进程一样都是OS中非常重要的部分,线程的应用场景非常的广泛,试想我们使用的视频软件,在网络不是很好的情况下,通常会采取下载的方式,现在你很想立即观看,又想下载,于是你点击了下载并且在…...

leetcode645. 错误的集合(java)
错误的集合 题目描述优化空间代码演示 题目描述 难度 - 简单 LC645 - 错误的集合 集合 s 包含从 1 到 n 的整数。不幸的是,因为数据错误,导致集合里面某一个数字复制了成了集合里面的另外一个数字的值,导致集合 丢失了一个数字 并且 有一个数…...

Pytest参数详解 — 基于命令行模式
1、--collect-only 查看在给定的配置下哪些测试用例会被执行 2、-k 使用表达式来指定希望运行的测试用例。如果测试名是唯一的或者多个测试名的前缀或者后缀相同,可以使用表达式来快速定位,例如: 命令行-k参数.png 3、-m 标记࿰…...

【python爬虫】3.爬虫初体验(BeautifulSoup解析)
文章目录 前言BeautifulSoup是什么BeautifulSoup怎么用解析数据提取数据 对象的变化过程总结 前言 上一关,我们学习了HTML基础知识,知道了HTML是一种用来描述网页的语言,又了解了HTML的基本结构。 认识了HTML中的常见标签和常见属性&#x…...

【Three.js + Vue 构建三维地球-Part One】
Three.js Vue 构建三维地球-Part One Vue 初始化部分Vue-cli 安装初始化 Vue 项目调整目录结构 Three.js 简介Three.js 安装与开始使用 实习的第一个任务是完成一个三维地球的首屏搭建,看了很多的案例,也尝试了用 Echarts 3D地球的模型进行构建…...

Power View
界面 切换可视化效果 对于已经上传到透视表的数据,选择power view,形成表格后。...

SQL查询本年每月的数据
--一、以一行数据的形式,显示本年的12月的数据,本示例以2017年为例,根据统计日期字段判断,计算总和,查询语句如下:selectsum(case when datepart(month,统计日期)1 then 支付金额 else 0 end) as 1月, sum…...
C++之struct和union对比介绍
C之struct和union对比介绍 在C中,struct和union都是用来定义自定义数据类型的关键字,但它们的作用略有不同。 首先了解一下它们的基本概念: struct(结构体):struct 是一个用户自定义的数据类型ÿ…...

微服务--SkayWalking(链路追踪:国产开源框架)
SkayWalking:分布式系统的应用程序性能监视工具 作用:分布式追踪、性能指标分析、应用、服务依赖分析; SkayWalking性能剖析: 我操,能够定位到某一个方法会有多慢。。。 通过Tid查看全局所有的日志信息(…...

在Windows 10上部署ChatGLM2-6B:掌握信息时代的智能对话
在Windows 10上部署ChatGLM2-6B:掌握信息时代的智能对话 硬件环境ChatGLM2-6B的量化模型最低GPU配置说明准备工作ChatGLM2-6B安装部署ChatGLM2-6B运行模式解决问题总结 随着当代科技的快速发展,我们进入了一个数字化时代,其中信息以前所未有的…...
LRU和LFU算法的简单实现
LRU #include <iostream> #include <unordered_map> #include <list> struct Node{int key;int value;Node(int key, int value):key(key),value(value){} }; class LruCache{ private:int maxCapacity;// 最大容量std::list<Node>CacheList;// 缓存链…...

OCR多语言识别模型构建资料收集
OCR多语言识别模型构建 构建多语言识别模型方案 合合,百度,腾讯,阿里这四家的不错 调研多家,发现有两种方案,但是大多数厂商都是将多语言放在一个字典里,构建1w~2W的字典,训练一个可识别多种语…...
倍增的经典题目:扩大区间、st表
1. 扩大区间 P4155 [SCOI2015] 国旗计划例题1:P4155 [SCOI2015] 国旗计划 计算能覆盖整个圆圈的最少区间,题目给定的所有区间互相不包含,按区间左端点排序后,区间的右端点也是单增的。 我们首先需要化圆为线,然后贪…...
LeetCode——和为K的子数组(中等)
题目 给你一个整数数组 nums 和一个整数 k ,请你统计并返回 该数组中和为 k 的连续子数组的个数 。 示例 1: 输入:nums [1,1,1], k 2 输出:2示例 2: 输入:nums [1,2,3], k 3 输出:2 题解 …...
Truncation Sampling as Language Model Desmoothing
本文是LLM系列文章,针对《Truncation Sampling as Language Model Desmoothing》的翻译。 截断采样作为语言模型的去平滑性 摘要1 引言2 背景3 截断作为去平滑性4 方法5 实验与结果6 相关工作7 结论8 不足 摘要 来自神经语言模型的长文本样本可能质量较差。截断采…...

docker安装jenkins
运行jenkins docker run -d \--name jenkins \ --hostname jenkins \-u root \-p 29090:8080 \--restart always \-v D:\springcloud\学习\jekins\jenkins\jks_home:/var/jenkins_home \ jenkins/jenkins获取root登录密码 密码在jekins_home/secrets/initalAdminPassword文件…...

学习pytorch8 土堆说卷积操作
土堆说卷积操作 官网debug torch版本只有nn 没有nn.functional代码执行结果 B站小土堆视频学习笔记 官网 https://pytorch.org/docs/stable/nn.html#convolution-layers 常用torch.nn, nn是对nn.functional的封装,使函数更易用。 卷积核从输入图像左上角…...

pytest自动化测试两种执行环境切换的解决方案
目录 一、痛点分析 方法一:Hook方法pytest_addoption注册命令行参数 1、Hook方法注解 2、使用方法 方法二:使用插件pytest-base-url进行命令行传参 一、痛点分析 在实际企业的项目中,自动化测试的代码往往需要在不同的环境中进行切换&am…...

Docker 离线安装指南
参考文章 1、确认操作系统类型及内核版本 Docker依赖于Linux内核的一些特性,不同版本的Docker对内核版本有不同要求。例如,Docker 17.06及之后的版本通常需要Linux内核3.10及以上版本,Docker17.09及更高版本对应Linux内核4.9.x及更高版本。…...
Spring Boot 实现流式响应(兼容 2.7.x)
在实际开发中,我们可能会遇到一些流式数据处理的场景,比如接收来自上游接口的 Server-Sent Events(SSE) 或 流式 JSON 内容,并将其原样中转给前端页面或客户端。这种情况下,传统的 RestTemplate 缓存机制会…...
Oracle查询表空间大小
1 查询数据库中所有的表空间以及表空间所占空间的大小 SELECTtablespace_name,sum( bytes ) / 1024 / 1024 FROMdba_data_files GROUP BYtablespace_name; 2 Oracle查询表空间大小及每个表所占空间的大小 SELECTtablespace_name,file_id,file_name,round( bytes / ( 1024 …...

23-Oracle 23 ai 区块链表(Blockchain Table)
小伙伴有没有在金融强合规的领域中遇见,必须要保持数据不可变,管理员都无法修改和留痕的要求。比如医疗的电子病历中,影像检查检验结果不可篡改行的,药品追溯过程中数据只可插入无法删除的特性需求;登录日志、修改日志…...

《从零掌握MIPI CSI-2: 协议精解与FPGA摄像头开发实战》-- CSI-2 协议详细解析 (一)
CSI-2 协议详细解析 (一) 1. CSI-2层定义(CSI-2 Layer Definitions) 分层结构 :CSI-2协议分为6层: 物理层(PHY Layer) : 定义电气特性、时钟机制和传输介质(导线&#…...
在四层代理中还原真实客户端ngx_stream_realip_module
一、模块原理与价值 PROXY Protocol 回溯 第三方负载均衡(如 HAProxy、AWS NLB、阿里 SLB)发起上游连接时,将真实客户端 IP/Port 写入 PROXY Protocol v1/v2 头。Stream 层接收到头部后,ngx_stream_realip_module 从中提取原始信息…...

跨链模式:多链互操作架构与性能扩展方案
跨链模式:多链互操作架构与性能扩展方案 ——构建下一代区块链互联网的技术基石 一、跨链架构的核心范式演进 1. 分层协议栈:模块化解耦设计 现代跨链系统采用分层协议栈实现灵活扩展(H2Cross架构): 适配层…...

【单片机期末】单片机系统设计
主要内容:系统状态机,系统时基,系统需求分析,系统构建,系统状态流图 一、题目要求 二、绘制系统状态流图 题目:根据上述描述绘制系统状态流图,注明状态转移条件及方向。 三、利用定时器产生时…...

WordPress插件:AI多语言写作与智能配图、免费AI模型、SEO文章生成
厌倦手动写WordPress文章?AI自动生成,效率提升10倍! 支持多语言、自动配图、定时发布,让内容创作更轻松! AI内容生成 → 不想每天写文章?AI一键生成高质量内容!多语言支持 → 跨境电商必备&am…...

Yolov8 目标检测蒸馏学习记录
yolov8系列模型蒸馏基本流程,代码下载:这里本人提交了一个demo:djdll/Yolov8_Distillation: Yolov8轻量化_蒸馏代码实现 在轻量化模型设计中,**知识蒸馏(Knowledge Distillation)**被广泛应用,作为提升模型…...