【Linux基础I/O】文件调用接口、文件描述符、重定向和缓冲区
【Linux基础I/O一】文件描述符和重定向
- 1.C语言的文件调用接口
- 2.操作系统的文件调用接口
- 2.1open接口
- 2.2close接口
- 2.3write接口
- 2.4read接口
- 3.文件描述符fd的本质
- 4.标准输入、输出、错误
- 5.重定向
- 5.1什么是重定向
- 5.2输入重定向和输出重定向
- 5.3系统调用的重定向dup2
- 6.缓冲区
1.C语言的文件调用接口
- fopen
FILE *fopen(const char *filename, const char *mode);
filename 参数是一个字符串,指定要打开的文件名或路径
mode 参数是一个字符串,指定文件的打开模式,常见如下:
“r”:只读,若文件不存在则报错
“w”:只写,若文件不存在则创建,打开时清空文件原有内容
“a”:只写,若文件不存在则创建,打开时从文件末尾追加
返回值:
如果成功打开文件,则返回指向 FILE 类型结构的指针,该指针用于后续的文件操作。
如果打开失败,返回 NULL,并且通过检查 errno 变量可以确定失败的具体原因
FILE *fp = fopen("temp.txt", "r");
if (fp == NULL) {perror("Error opening file");return 1;
}
- fclose
int fclose(FILE *stream);
stream 是一个指向 FILE 结构的指针,指定要关闭的文件
返回值:
如果成功关闭文件,则返回 0。
如果关闭失败,则返回 EOF
FILE *fp = fopen("temp.txt", "r");
if (fp == NULL) {perror("opening error");return 1;
}if (fclose(fp) == 0) {printf("close succeed.\n");
} else {perror("closing error");return 1;
}
- fprintf
int fprintf(FILE *stream, const char *format, ...);
stream是一个指向FILE结构的指针,指定要写入的目标文件
format是一个格式化字符串,类似于printf函数中的格式化字符串,用于指定输出的格式
返回值:
成功返回写入的字符数,如果出错则返回一个负数
默认打开文件的时候,清空文件内容
a打开方式:append追加方式写入文件,不会清空原文件内容
2.操作系统的文件调用接口
2.1open接口
pathname 是一个字符串,表示要打开的文件路径
flags 是打开文件的标志位,例如O_RDONLY
(只读)、O_WRONLY
(只写)、O_RDWR
(读写)、O_CREAT
(若打开的文件不存在,则创建该文件)
mode 是文件的权限,通常与 flags 参数中的某些标志结合使用,用于指定文件的创建模式
返回值:
如果成功,返回一个新的文件描述符,用于后续的文件操作
如果出错,返回 -1
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>int main()
{int fd = open("log.txt", O_WRONLY | O_CREAT);return 0;
}
运行./mybin后,当前目录就出现了文件log.txt了,但是它的权限值是乱码-r-s–x–T,如果你删掉该文件后再次运行代码,你会发现下一次的权限值和上次还不一样
此时就需要三个参数的open接口:
mode用于控制文件的初始权限,一般系统默认掩码是0002
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>int main()
{int fd = open("log.txt", O_WRONLY | O_CREAT, 0666);return 0;
}
open的第三个参数传入0666,也就是log.txt的初始权限
由于umask是0002,所以最终权限为664也就是rw-rw-r–
2.2close接口
作用:关闭文件
描述符fd对应的文件, 调用成功返回0
2.3write接口
fd:被写入文件的fd
buf:指向被写入的字符串
count:写入字符的个数
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>int main()
{int fd = open("log.txt", O_WRONLY | O_CREAT, 0666);char* str = "Hello\n Hello\n";write(fd, str, 6);close(fd);return 0;
}
向log.txt写入了一个字符串str,write的第三个参数为6,只写入了6个字符Hello\n,输出结果是Hello
在保留原先log.txt的情况下,更改test.c:
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>int main()
{int fd = open("log.txt", O_WRONLY | O_CREAT, 0666);char* str = "Hello\n Hello\n";write(fd, str, 6);close(fd);return 0;
}
log.txt的内容变成了123lo,为什么?
以O_WRONLY模式对文件进行写入时,不会先把文件内容清空,而是直接从头开始覆盖
有两种解决方案,对应两个open的选项
O_TRUNC
打开时清空文件内容O_APPEND
以追加的形式写入
2.4read接口
fd:目标文件的文件描述符fd
buf:将文件内容读取到buf指向的空间中
count:最多读取count个字节的内容
返回值:
< 0:读取发送错误
= 0:读取到文件末尾
0:读取成功,返回读取到的字符个数
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <string.h>int main()
{int fd = open("log.txt", O_RDONLY);char buffer[1024];ssize_t ret1 = read(fd, buffer, 1024);printf("ret1 = %ld\n", ret1);printf("%s", buffer);close(fd);return 0;
}
在系统创建一个log.txt文件,内容为字符串hello Linux
一开始用open以只读RDONLY形式打开文件,通过read(fd, buffer, 1024)
把内容存储到数组buffer中,并把返回值交给ret1,随后输出ret1和buffer
第一次read返回值为12,也就是字符串Hello Linux有12个字符
3.文件描述符fd的本质
文件描述符的本质是一个数组的下标
在Linux系统下,一切皆文件
文件 = 内容 + 属性
文件操作 = 对内容的操作 或 对属性的操作
因为冯诺依曼体系结构,CPU只和内存做交互,所以要对文件做修改就需要加载到内存
我们会同时打开多个文件,也会有别人同时打开文件,所以,操作系统需要管理这些打开的文件
管理 = 先描述,再组织
操作系统同样会像管理进程那样,也给文件创建对应的结构体,然后文件之间会有一些连接关系
这样,对文件的管理就变成对某种数据结构的管理
文件操作是用户让操作系统进行的,操作系统会为此创建进程
所以文件操作实质是进程和被打开文件的关系
操作系统运行时,会有很多进程在运行
在文件没有被打开之前,文件是存在磁盘中的
打开文件是进程打开的:进程将文件的数据加载到文件内核级的缓存块中
而一个进程能打开很多文件,同时,系统当中可以存在许多进程
为了更好的管理文件,所有被打开的文件,操作系统都会对其创建一个结构体struct file
文件 = 属性 + 内容,而这个struct file结构体对象就是用来描述被打开的文件
被打开的文件结构体对象,被操作系统用双向链表组织起来,成为一个双向链表
于是,操作系统对被打开文件的管理就变成了对一个双向链表的增删查改,解决了对文件的管理问题
文件和进程之间的关系如何描述和组织?
进程的PCB(task_struct)结构体对象中存在一个指针变量:struct files_struct *file
在Linux 2.6.10内核中,struct files_struct如下:
其最后一个成员fd_array
是一个数组,指向的成员类型为struct file*
,也就是指向struct file的指针
struct files_struct {atomic_t count;spinlock_t file_lock;/* Protects all the below members. Nests inside tsk->alloc_lock */int max_fds;int max_fdset;int next_fd;struct file ** fd;/* current fd array */fd_set *close_on_exec;fd_set *open_fds;fd_set close_on_exec_init;fd_set open_fds_init;struct file * fd_array[NR_OPEN_DEFAULT];
};
操作系统全局管理的struct files_struct
,整个系统中所有被打开的文件都要被这个结构体管理
每个进程自己打开维护的struct files_struct
,分别管理自己打开的文件
这个指针数组内部的一个个指针就对应着一个个被打开的文件的地址
而文件描述符fd就是这个数组的下标
所以,当用户想要访问一个进程下的文件时,因为每一个进程的PCB是唯一的,所以文件管理数组也唯一的,只要是进程打开了一个文件,就会把文件的*file
添加进去
只需要返回这个进程PCB结构体中fd_array
数组的下标
就可以找到对应的文件了
下述三个系统调用函数都有一个int fd,当打开一个文件时,
要对这个文件进行写、读、操作,都需要传递open时返回的文件描述符fd
用fd去找到对应的文件然后执行相关操作
对文件的读写等操作的数据改动都是在缓冲区内进行
然后由操作系统刷新到磁盘对应位置
所以,读取文件,本质上就是从文件的文件内核缓冲区内加载数据到应用层的用户级缓冲区
4.标准输入、输出、错误
0:标注输入 (键盘)
1:标准输出 (显示器)
2:标准错误 (显示器)
int fd1 = open("text1.txt",O_WRONLY | O_CREAT);
int fd2 = open("text2.txt",O_WRONLY | O_CREAT);
int fd3 = open("text3.txt",O_WRONLY | O_CREAT);
int fd4 = open("text4.txt",O_WRONLY | O_CREAT);printf("fd1 = %d\nfd2 = %d\nfd3 = %d\nfd4 = %d\n",fd1,fd2,fd3,fd4);
确实多出了4个,文件文件描述符从3开始,编号0 1 2的fd去哪里了?
C语言中,会为我们默认打开三个流stdin
标准输入,stdout
标准输出,stderr
标准错误,0、1、2为编号的fd就已经被占用
C语言中,文件流是以FILE的形式被管理的,毫无疑问FILE是对Linux文件系统的封装,FILE内部一定存储了fd,否则无法通过fd来访问特定的文件,其中FILE的_fileno成员就是fd
#include <stdio.h>int main()
{int fd1 = stdin->_fileno;int fd2 = stdout->_fileno;int fd3 = stderr->_fileno;printf("stdin->_fileno = %d\n", fd1);printf("stdout->_fileno = %d\n", fd2);printf("stderr->_fileno = %d\n", fd3);return 0;
}
LInux下一切皆文件:
在Linux操作系统中的每一个驱动设备都创建了struct file结构体
结构体内部的属性就是设备的属性数据和函数指针
所以,尽管每一个设备的操作方法不一样,但可以把方法的返回值、参数设置成一样的,然后让这些函数指针指向底层的硬件设备的操作方法,站在Linxu的角度来看这些硬件,也视为文件
实现这种组织的技术其实就是多态
所以对于硬件这一层,在Linux下叫做vfs,即vitural file system虚拟软件系统
5.重定向
5.1什么是重定向
文件描述符的分配规则:查看自己的文件描述表,分配最小的没有被使用的fd
printf和scanf作为C语言的函数接口,同样无法直接和显示器和键盘作交互,其必须依靠相应的文件,也就是标准输出和标准输入
但是依靠的指向并不是FILE*,而是文件描述符,printf依靠1号文件,scanf依靠0号文件
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>int main()
{close(1);//关掉1号文件(stdout)int fd1 = open("log.txt",O_WRONLY | O_CREAT | O_APPEND,0666);//打开log.txtprintf("Hello Linux\n");//向屏幕打印printf("Hello Linux\n");printf("Hello Linux\n");printf("Hello Linux\n");return 0;
}
可以看到Hello Linux
并没有如愿打印在屏幕上,因为printf只往1号文件里写,就算使用fprintf向stdout输出也不会输出到屏幕
说明printf函数和stdout只认文件描述符1,不管1此时还是不是
标准输出
但1号文件被关闭,系统给新文件log.txt分配最小的没有被使用的fd,也就是1号,所以本来写入到显示器里的内容写入到了log.txt
这就是重定向,重定向的本质:是在内核中改变文件描述符表特定下标的内容
5.2输入重定向和输出重定向
>
代表输出重定向,将输出从显示器更改到指定文件
<
代表输入重定向,将输入从键盘更改到指定文件
测试:
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>int main()
{printf("printf->stdout\n");fprintf(stdout,"fprintf->stdout\n");fprintf(stderr,"fprintf->stderr\n");return 0;
}
直接运行会向显示器打印
重定向后标准输出被重定向到文件中了,但是标准错误仍然还是输出到显示器中
因为
>
是输出重定向,只会更改标准输出stdout的文件描述符,也就是将指向显示器的文件描述符1更改指向log,txt,但是并不会更改标准错误stderr的文件描述符2,所以标准错误依然写入到显示器上,只有标准输出写入到了指定的文件中
>
:将命令的标准输出重定向到文件,会覆盖文件内容。
<
:将文件内容作为命令的标准输入。
>>
:将命令的标准输出重定向到文件,追加到文件末尾,不会覆盖文件内容。
5.3系统调用的重定向dup2
操作系统提供一个专门用于文件描述符改向的系统调用就叫做dup2
oldfd:原始文件描述符,表示要复制的文件描述符。
newfd:目标文件描述符,表示将 oldfd复制给的newfd
返回值:
成功时dup2 返回 newfd(复制操作后新的文件描述符)
失败时返回 -1,并将 errno 设置为相应的错误代码。
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>int main()
{int fd;// 打开文件,如果文件不存在则创建,权限为0644fd = open("output.txt", O_WRONLY | O_CREAT | O_TRUNC, 0644);// 将标准输出重定向到fddup2(fd, STDOUT_FILENO);//STDIN_FILENO和STDOUT_FILENO是C语言标准库中定义的宏,分别用于表示标准输入和标准输出的文件描述符,这两个宏在<unistd.h>头文件中定义,通常被赋值为0和1printf("Hello Linux\n");// 关闭原文件描述符close(fd);return 0;
}
6.缓冲区
缓冲区本质上就是一块内存区域
fwrite
等C语言的文件IO接口,都在底层封装了系统调用接口write
,用户调用的所有C语言文件IO接口,都会先写到缓冲区中,然后等到一定条件,在通过一次系统调用,把之前所有缓冲区的数据写入到操作系统中,这个一次性写入过程叫做刷新缓冲区
操作系统也有自己的缓冲区,但是这个是操作系统自己管理的内核缓冲区,其决定了wirte等系统调用接口写入的数据何时写入到内存中,但不是该博客讨论的范围,后续讨论的缓冲区都是用户级缓冲区(语言级别的文件缓冲区)
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>int main()
{close(1);int fd = open("myfile.txt", O_WRONLY|O_CREAT, 0666);printf("fd: %d\n", fd);//fflush(stdout);close(fd);exit(0);//中断程序}
当运行上述代码时,即使对一个文件写入了内容,也没有显示
使用了fflush函数之后,就显示了
原因就是struct FILE 结构体内还有一个语言级别的文件缓冲区
我们使用的printf、fprintf函数等写入的数据都是写到了语言级别的文件缓冲区,而不是到了内存的缓冲区
所以fflush函数所作的工作其实就是把语言级别的缓冲区刷新到内存中
所以如果在文件关闭之前,没有进行刷新,那么,就无法把语言级的缓冲区刷新到内存
用户级缓冲区的刷新策略有以下几种:
1.无缓冲:不进行缓冲,直接输出
2.行缓冲:向显示器写入时,'\n’会强制刷新缓冲区,也就是一行一行刷新缓冲区
3.全缓冲:向普通文件写入时,一般缓冲区被写满才会刷新
4.程序结束,强制刷新缓冲区
5.用户调用flush函数,强制刷新缓冲区
缓冲区被struct FILE管理,由于每个文件的FILE是独立的,因此每个文件的缓冲区也是独立的
特殊情况:
#include <stdio.h>
#include <unistd.h>
#include <string.h>int main()
{fprintf(stdout,"fprintf->stdout\n");char* temp = "write\n";write(1,temp,strlen(temp));fork();return 0;
}
我们成功将内容输出到了显示器
但是,当我们将这些内容重定向到文件中,C语言库的输出打印了两次
为什么write不打印两次?
当我们重定向时,write是系统调用,直接写入struct file的缓冲区(文件内核的缓冲区)
为什么fprintf在fork之前就已经完成了却打印了两次?
fprintf因为是语言层面的调用,将内容写入FILE结构体的缓冲区(语言级别的文件缓冲区),原本向显示器输出的策略是行刷新,但在重定向到log.txt前还没有行刷新将其打印,所以fprint->stdout
就被留在了缓冲区
当子进程被创建时会继承父进程的数据和代码,stdin的FILE指向的缓冲区也会被继承
所以当父子进程同时进行至刷新缓冲区时,分别输出了一句fprint->stdout
相关文章:
【Linux基础I/O】文件调用接口、文件描述符、重定向和缓冲区
【Linux基础I/O一】文件描述符和重定向 1.C语言的文件调用接口2.操作系统的文件调用接口2.1open接口2.2close接口2.3write接口2.4read接口 3.文件描述符fd的本质4.标准输入、输出、错误5.重定向5.1什么是重定向5.2输入重定向和输出重定向5.3系统调用的重定向dup2 6.缓冲区 1.C语…...
软考中级软件设计师——操作系统考试题型
一、PV操作与进程同步(必考大题) 1. 真题示例(2020年真题) 题目: 三个进程P1、P2、P3共享一个缓冲区,P1生产数据放入缓冲区,P2和P3消费数据。要求: 缓冲区大小为10,满时…...
transformer归一化层优化:深度解读 RMSNorm (Root Mean Square Layer Normalization,均方根层归一化)
导读:RMSNorm 把传统 LayerNorm 的“减均值(centering) 除标准差(scaling)”简化为“直接除以向量均方根 (Root Mean Square, RMS,均方根)”。这一改动让归一化既 更省算 又 同样稳定,因而成为 …...
java基础 之 Hash家族(一)
文章目录 HashCode定义代码使用使用场景 HashMap定义常用方法使用场景 ConcurrentHashMap定义常用方法使用场景 HashTable定义常用方法使用场景 HashSet定义常用方法使用场景你想到过吗? HashMap、ConcurrentHashMap、HashTable的对比总结 HashCode 定义 hashcode是…...
windows服务器部署jenkins工具(二)
jenkins的大致流程:新增任务->配置任务->构建(打包)项目->部署(发布) 具体如何使用,我这里就不多讲了。这次就给大家讲讲,jenkins安装之后使用过程中存在的一些问题。 1.maven项目如…...
机器学习第二十讲:网格搜索 → 像尝试所有密码组合找最佳解锁方式
机器学习第二十讲:网格搜索 → 像尝试所有密码组合找最佳解锁方式 资料取自《零基础学机器学习》。 查看总目录:学习大纲 关于DeepSeek本地部署指南可以看下我之前写的文章:DeepSeek R1本地与线上满血版部署:超详细手把手指南 网…...
【人工智能发展史】从黎明到曙光01
人工智能的史诗:从黎明到曙光 序曲:晨曦微露 故事的序幕拉开于一个思想激荡的年代,1956年,达特茅斯会议的钟声,如同第一缕晨曦,宣告了"人工智能"纪元的到来。那个夏天,在新罕布什尔…...
ollama使用gpu运行大模型
罗列ollma镜像 ollama list拉取ollama镜像源里面的模型: ollama pull qwen2:1.5b下载CudaToolkit https://developer.nvidia.com/cuda-toolkit-archive 我这里选择11.7的万金油版本,从来没出过bug Ollama安装好后,为了让推理跑在GPU上&am…...
Linux电源管理——PSCI初始化流程和多核启动流程
目录 一、PSCI 初始化流程 1、PSCI设备树节点 2、PSCI kernel初始化流程 get_set_conduit_method set_conduit psci_probe 二、CPU PSCI 操作初始化流程 1、CPU 设备树节点 2、 struct cpu_operations 3、kernel 流程 cpu_read_bootcpu_ops smp_init_cpus 三、CPU…...
Linux问题排查-引起服务器带宽使用率高的内鬼
Linux网络流量监控与瓶颈分析全攻略:从基础命令到进程级方案 一、网络带宽查询与实时流量监控 1. 查询主机网络带宽 网卡理论带宽 通过ethtool命令查看网卡最大支持速率,例如: ethtool eth0 # 替换为实际网卡名(如ens33&#x…...
《微服务架构设计模式》笔记
思维导图 1-3章 4-6 章 5-13 章 资料 配套代码仓库:https://github.com/microservices-patterns/ftgo-application 作者网站:https://microservices.io/...
基于JDBC的信息管理系统,那么什么是JDBC呢?
JDBC 即 Java Database Connectivity,是 Java 语言中用于与数据库进行交互的一套 API。它提供了一种标准的方式,让 Java 程序能够连接到各种不同类型的数据库,并执行 SQL 语句来实现对数据库的查询、插入、更新和删除等操作。 主要功能 建立…...
百度地图的地铁图API所有城市的城市名和citycode的对照关系列表
百度地图的地铁图API所有城市的城市名和citycode的对照关系列表 城市keywordcitycode北京beijing131上海shanghai289广州guangzhou257深圳shenzhen340重庆chongqing132天津tianjin332石家庄shijiazhuang150南京nanjing315成都chengdu75沈阳shenyang58杭州hangzhou179武汉wuhan2…...
信息学奥赛一本通 1853:【08NOIP提高组】传纸条 | 洛谷 P1006 [NOIP 2008 提高组] 传纸条
【题目链接】 ybt 1853:【08NOIP提高组】传纸条 洛谷 P1006 [NOIP 2008 提高组] 传纸条 【题目考点】 1. 动态规划:坐标型动态规划 【解题思路】 抽象问题,存在m乘n的网格,每个格子中有一个数值,即同学愿意帮忙的…...
APM32小系统键盘PCB原理图设计详解
APM32小系统键盘PCB原理图设计详解 一、APM32小系统简介 APM32微控制器是国内半导体厂商推出的一款高性能ARM Cortex-M3内核微控制器,与STM32高度兼容,非常适合DIY爱好者用于自制键盘、开发板等电子项目。本文将详细讲解如何基于APM32 CBT6芯片设计一款…...
【Linux我做主】探秘进程与fork
进程和fork 父子进程和forkgithub地址前言1. 进程的标识符PID1.1 查看系统内所有的进程1.2 kill杀掉进程1.3 获取进程的PID1.4 bash与父子进程 2. 创建进程与fork2.1 fork创建子进程2.2 fork困惑的解释0. fork的工作原理1. 为什么给子进程返回0,给父进程返回子进程P…...
学习python day4
1.顺序语句结构 #赋值语句 name张三 age20 a,b,c,droom#字符串分解赋值 print(a,b,c,d) #输入输出也是典型的顺序结构 nameinput(请输入您的姓名:) ageeval(input(请输入您的年龄:)) #使用eval进行转换 print(姓名:,name) print(年龄&#x…...
如何通过外链建设提升Shopify独立站的权重和排名
一、外链质量评估与筛选原则 相关性优先 选择与自身行业、产品或目标用户群体高度相关的网站(如行业论坛、垂直媒体、评测博客)交换外链,避免低相关性垃圾链接导致搜索引擎惩罚。 权威性指标 关注外链来源网站的域名权威(DA…...
高并发内存池|六、page cache的设计
六、page cache的设计 1. page cache的结构 page cache 也是一个哈希桶结构,但它的映射结构与前两个 cache 不同。它的每一个桶是容量从 1 到 128 页大小的内存块,桶中的每个内存块由 SpanList 管理。page cache 的内存由其向系统申请所得,…...
C++线程池实现
C线程池实现 知识点补充为什么要实现线程池线程池的实现过程 知识点补充 在C11中引入了对线程库的支持,接下来我们介绍一下跟线程相关的一些知识点: 线程对象的构造方式 在C11中主要提供的三种线程的构造方式:无参构造、带参构造和调用移动构…...
#Redis缓存篇#(七)分布式缓存
目录 一 单节点Redis 1 单节点的问题 二 分布式缓存 1 Redis持久化 (1 RDB持久化 (2 AOF持久化 2 Redis主从集群 (1 搭建主从架构 (2 主从数据同步原理 3 Redis哨兵 (1 哨兵的作用和原理 (2 搭…...
【VSCode】安装与 ssh 免密登录
【VSCode】安装与 ssh 免密登录 下载SSH 登录设置免密登录关闭远程连接删除ssh连接(慎用!!!删除了建立的连接就没有了!!) 下载 https://code.visualstudio.com/docs/?dvwin64user 选择安装路径…...
【Python解决八皇后问题】回溯算法与优化策略全解析
目录 🌟 前言🏗️ 技术背景与价值🩹 当前技术痛点🛠️ 解决方案概述👥 目标读者说明🧠 一、技术原理剖析📊 核心概念图解💡 核心作用讲解🔧 关键技术模块说明⚖️ 技术选型对比🛠️ 二、实战演示⚙️ 环境配置要求💻 核心代码实现基础回溯实现位运算优化…...
判断一个元素是否在可视区域
判断元素是否在可视区域的方法 方法一:offsetTop 和 scrollTop 通过计算元素的 offsetTop 和容器的 scrollTop 来判断元素是否位于视口内。这种方法适用于简单的垂直滚动场景。 优点: 实现简单,性能较好。缺点: 不支持复杂的布局结构(如嵌套滚动),无法处理水平方向上的可…...
作物遗传与种质创新利用全国重点实验室-随笔10
作物遗传与种质创新利用全国重点实验室依托于南京农业大学,2022年11月完成国家重点实验室重组工作,由原名称“作物遗传与种质创新国家重点实验室”正式更名为“作物遗传与种质创新利用全国重点实验室”。 实验室面向国家粮食安全和农业高质量发展的重大战…...
分布式电源的配电网无功优化
分布式电源(Distributed Generation, DG)的大规模接入配电网,改变了传统单向潮流模式,导致电压波动、功率因数降低、网损增加等问题,无功优化成为保障配电网安全、经济、高效运行的关键技术。 1. 核心目标 电压稳定性:抑制DG并网点(PCC)及敏感节点的电压越限(如超过5%…...
游戏引擎学习第301天:使用精灵边界进行排序
回顾并为今天的内容做准备 昨天,我们解决了一些关于排序的问题,这对我们清理长期存在的Z轴排序问题很有帮助。这个问题我们一直想在开始常规游戏代码之前解决。虽然不确定是否完全解决了问题,但我们提出了一个看起来合理的排序标准。 有两点…...
网络框架二次封装:基于Kotlin的高扩展性网络请求框架完整实现
完整目录结构 1. 架构设计1.1 分层架构1.2 核心组件1.3 接口关系图2. 基础配置实现2.1 NetworkConfig完整代码2.2 CacheConfig完整代码3. 核心网络客户端3.1 SmartHttpClient完整实现3.2 单例管理3.3 服务创建与执行4. DSL请求构建器4.1 NetworkRequest完整实现4.2 生命周期绑…...
高噪声下扩展边缘检测算子对检测边缘的影响
目录 一、常见的边缘检测算子 二、扩展边缘检测算子对检测边缘的影响 三、结论 一、常见的边缘检测算子 Sobel 算子: Prewitt算子;...
Linux 内核音视频架构(V4L2 )介绍
一.概述 Linux 内核中的 V4L2(Video for Linux Two)框架 是用于管理音视频设备(如摄像头、电视调谐器、视频采集卡等)的核心子系统。 它提供了一套统一的接口,使得用户空间应用程序能够方便地访问和控制硬件设备&…...
专业 YouTube SEO 方案:打造高排名视频的关键步骤
YouTube 是全球订阅量最高的社交媒体平台之一。YouTube 为发布创意视频内容和针对特定受众开展营销活动提供了无限可能,是任何品牌内容营销策略的重要组成部分。 但是,为了发展您的 YouTube 频道并消除噪音,优化您的视频内容以便可以在搜索结…...
基于STM32的智能台灯_自动亮度_久坐提醒仿真设计(Proteus仿真+程序设计+设计报告+讲解视频)
这里写目录标题 1.主要功能2.仿真设计3.程序设计4.设计报告5.下载链接 基于STM32的智能台灯_自动亮度_久坐提醒仿真设计 (Proteus仿真程序设计设计报告讲解视频) 仿真图Proteus 8.9 程序编译器:keil 5 编程语言:C语言 设计编号࿱…...
labview硬件部分——压力测量
0kg的电压需要我们手动输入!在不放东西的时候的电压,先运行一次程序,将其记录后写到程序中的0kg输入按键即可。 整体的程序:...
Mysql索引实战1
对于上面这两种 name>‘a’ 和 name>‘zzz’ 的执行结果,mysql最终是否选择走索引或者一张表涉及多个索引,mysql最终如何选择索引,我们可以用trace工具来一查究竟,开启trace工具会影响mysql性能,所以只能临时分析…...
在实际网络部署中,静态路由的优先级通常高于RIP
是的,在实际网络部署中,静态路由的优先级通常高于RIP,尤其是在中小型网络或对可控性要求高的场景中。以下是关键原因和典型应用场景分析: 1. 为何静态路由比RIP更受青睐? (1) 简单性与可靠性 静态路由: 手…...
Linux系统编程-DAY02
一、标准io 1.写文件 fgets函数中判断有多少行,且判断最后一个是不是终止符 if( buf[strlen(buf) - 1] \n ) 2. wc命令行:字符统计 wc -l 文件名 行数 文件名 3. write 用于操作二进制的文件(文办文件和图片文件也可以…...
【C++ 真题】P5736 【深基7.例2】质数筛
P5736 【深基7.例2】质数筛 题目描述 输入 n n n 个不大于 10 5 10^5 105 的正整数。要求全部储存在数组中,去除掉不是质数的数字,依次输出剩余的质数。 输入格式 第一行输入一个正整数 n n n,表示整数个数。 第二行输入 n n n 个正…...
自制操作系统day6(GDTR、段描述符、PIC、实模式和保护模式、16位到32位切换、中断处理程序、idt的设定、EFLAG寄存器)(ai辅助整理)
day6 分割源文件(harib03a) 优点 按照处理内容进行分类,如果分得好的话,将来进行修改时,容易找到地方。如果Makefile写得好,只需要编译修改过的文件,就可以提高make的速度。单个源文件都不长。…...
大模型评测与可解释性
随着大模型在各个领域展现出惊人的能力,我们对其性能的评估和对其决策过程的理解变得尤为重要。一个模型即使在基准测试中表现出色,也可能在实际应用中遇到意想不到的问题。同时,由于大模型的复杂性,它们常常被视为“黑箱”,这给其在关键领域的应用带来了挑战。 本章将深…...
【TTS回顾】StyleTTS 深度剖析:TTS+风格迁移
写在前面 这篇博客我们回顾一下StyleTTS,当时的背景是,文本转语音(TTS)技术,早已不再满足于仅仅将文字转化为可听的语音。行业需要的是“真人TTS”,AI 不仅能“说得清楚”,更能“说得生动”、“说得有感情”,甚至能模仿特定人物的说话风格。富有表现力的语音合成,即能…...
GStreamer (四)交叉编译
交叉编译 下载链接库交叉编译1、下载Gstreamer (方式二 ),进入到编译目录2、在gst-build目录下创建交叉编译配置文件cross_file.txt3、修改meson_options.txt中libmount选项为false,否则编译前需要先编译libmount。4、在gst-build…...
电路设计基础
只有当电容两端的电压等于0伏的时候,就是这一点的电压和这一点电压之间没有压差的时候,我门才可以把电容当成是一根导线,如果当我电容比如说它己经充到有一个1伏的电压了,这个时候我们是不可以把电容当成是导线的,所以…...
C语言——函数递归与迭代
(1)递归的例子: 顺序打印一个整数,打印整数的每一位。 例如: input:1234 output:1 2 3 4 input:520 output:5 2 0 我们可能会想到用这种方法:(但是运行之后,我们发现结果是事…...
详解 C# 中基于发布-订阅模式的 Messenger 消息传递机制:Messenger.Default.Send/Register
🧑 博主简介:CSDN博客专家、CSDN平台优质创作者,高级开发工程师,数学专业,10年以上C/C, C#, Java等多种编程语言开发经验,拥有高级工程师证书;擅长C/C、C#等开发语言,熟悉Java常用开…...
8 种快速易用的Python Matplotlib数据可视化方法
你是否曾经面对一堆复杂的数据,却不知道如何让它们变得直观易懂?别慌,Python 的 Matplotlib 库是你数据可视化的最佳伙伴!它简单易用、功能强大,能将枯燥的数字变成引人入胜的图表。无论是学生、数据分析师还是程序员&…...
嵌入式开发学习日志(linux系统编程--文件读写函数(2))Day25
一、linux操作命令 【wc】:指定字符统计; 【file 文件名】:可以查看文件的类型; 二、写入函数【fwrite】————可写入二进制文件 形式: size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE…...
离线服务器Python环境配置指南
离线服务器Python环境配置指南:避坑与实战 0. 场景分析:当服务器与世隔绝时 典型困境: 无法访问国际网络(如PyPI、Conda官方源)服务器处于内网隔离环境安全策略限制在线安装 解决方案矩阵: 方法适用场…...
Java线程池调优与实践经验
在Java面试中,线程池调优是一个常见且重要的考察点,尤其是当涉及Spring生态时,ThreadPoolTaskExecutor的使用经验通常会被深入追问。以下是针对该问题的结构化回答,结合原理、实践和调优经验: 1. 线程池调优的核心参数…...
Python 包管理工具核心指令uvx解析
uvx 是 Python 包管理工具 uv 的重要组成部分,主要用于在隔离环境中快速运行 Python 命令行工具或脚本,无需永久安装工具包。以下是其核心功能和使用场景的详细解析: 一、uvx 的定位与核心功能 工具执行器的角色 uvx 是 uv tool run 的别名&a…...
力扣-三数之和
1.题目描述 2.题目链接 LCR 007. 三数之和 - 力扣(LeetCode) 3.题目代码 import java.util.*; class Solution {public List<List<Integer>> threeSum(int[] nums) {Arrays.sort(nums);int tempnums.length-1;Set<List<Integer>…...