深入了解linux系统—— 基础IO(上)
文件
在之前学习C
语言文件操作时,我们了解过什么是文件,这里简单回顾一下:
文件存在磁盘中,文件有分为程序文件、数据文件;二进制文件和文本文件等。
详细描述见文章:文件操作——C语言
- 文件在磁盘里,磁盘是永久性存储介质,因为文件在磁盘上的存储是永久性的;
- 磁盘是外设(是输入设备也是输出设备);
- 本质上对磁盘是文件的所有操作,都是对外设的输入和输出;也就是
I/O
。
对于文件的认识:
- 文件 = 文件内容 + 文件属性
- 文件大小是
0
KB的文件也是占用磁盘空间的- 所有对于文件的相关操作都是对文件内容和文件属性就行操作。
在系统层面理解
- 我们操作文件(打开,关闭文件),本质上是进程对于文件的操作;
- 磁盘的管理者是操作系统;
- 我们在C/C++使用库函数来对文件进行读写操作,本质上是通过文件相关的系统调用去完成的。
C
文件操作
打开和关闭文件
在C
语言当中,我们通过fopen
来打开文件,fclose
来关闭文件;
fopen
:打开文件,如果打开成功返回一个FILE*
类型的指针,执行被打开的文件;打开失败则返回NULL
;fclose
:关闭文件,传参FILE*
类型的指针,关闭指定文件。
#include <stdio.h>
int main()
{ FILE* fp = fopen("log.txt","w");//以读方式打开,文件不存在就新建 if(fp == NULL){ perror("fopen"); return 1; } //.... fclose(fp);//关闭文件 return 0;
}
打开文件的方式
我们知道在C
语言的fopen
接口打开文件是有很多打开方式
r
:以读方式打开、w
以写方式打开、a
以追加方式打开。
r
方式,当文件不存在时就打开文件失败;
w
方式,当文件不存在时就新建文件(在当前工作路径下创建,进程
当中存放了当前工作路径);如果文件存在会清空当前文件的内容;然后在进入写入。
a
方式,追加,当文件不存在就新建文件;如果文件已经存在,打开时不会清空文件内容,而是在文件末尾进行写入
写文件
当我们以w
/r
方式打开一个文件,我们要将内容写到文件当中;
我们可以使用fputc
、fputs
、fwrite
、fprintf
进行文件的写入;
#include <stdio.h>
int main()
{ FILE* fp = fopen("log.txt","w");//以读方式打开,文件不存在就新建 if(fp == NULL){ perror("fopen"); return 1; } for(char ch = 'a';ch <= 'z';ch++){ fputc(ch,fp); } char* str = (char*)"I love you\n"; fputs(str,fp); int x = 100; fprintf(fp,"x = %d\n",x); fclose(fp);//关闭文件 return 0;
}
文件读取
我们以r
方式打开一个文件,我们要像读取这个文件的内容,我们可以使用fgetc
、fgets
、fscanf
进入文件内容的读取操作:
#include <stdio.h>
int main()
{ FILE* fp = fopen("log.txt","w");//以读方式打开,文件不存在就新建 if(fp == NULL){ perror("fopen"); return 1; }for(int i = 0;i<26;i++){ printf("%c",fgetc(fp)); } printf("\n"); char buff[20]; fgets(buff,12,fp); //buff[11] = '\0'; printf("%s",buff); int x; fscanf(fp,"x = %d",&x); printf("x = %d\n", x); fclose(fp);//关闭文件 return 0;
}
stdin/stdout/stderr
在我们程序运行时,C
语言它会默认打开三个文件:stdin
、stdout
和stderr
;
我们可以发现这三个都是文件类型指针
系统文件I/O
在上述C
语言的文件操作fopen
、fclose
都是语言层提供给我们的文件操作接口;以及C
语言的stdin
、stdout
、stderr
;C++中的cin
、cout
、cerr
都是语言层提供给我们的方案;
我们知道文件的管理者是操作系统,所以我们对文件操作都要经过操作系统;
那也就是说语言层的文件操作接口,其底层都封装了系统调用。
1. 传递多个标志位的方法
在之前的习惯中,我们通常使用一个参数来作为一个标记位;这样我们在传递多个标志位时就需要传递多个参数。
现在来了解一种使用一个参数来传递多个标志位的方法:
使用一个
bit
为来作为一个标识符,这样使用一个参数就可以表示多个标志位了。
#include <stdio.h>
#define ONE 0001 //0000 0001
#define TWO 0002 //0000 0010
#define THREE 0004 //0000 0100
void func(int flag){ if(flag & ONE) printf("ONE "); if(flag & TWO) printf("TWO "); if(flag & THREE) printf("THREE "); printf("\n");
}
int main()
{ func(ONE); func(ONE | TWO); func(ONE | THREE); func(ONE | TWO | THREE); return 0;
}
这样就可以使用一个参数,传递多个标志位了。
Linux
操作系统open
接口就使用了一个参数来传递多个标志位。
2. 打开文件open
在语言层面,我们使用的fopen
,它本质上就是对系统调用的封装;
可以看到
open
是一个系统调用;它的作用就是打开一个文件,也可能会创建一个新的文件。
我们可以看到open
函数它存在一个两个参数的,也存在一个三个参数的;
pathname
:表示要打开文件的文件名(不带路径就默认在当前工作路径下)flags
:表示文件的打开方式,存在多个标志位mode
:表示新建文件时,文件的默认权限
文件名pathname
这个想必就不用多说了,表示要打开文件的文件名;
不带路径时,就表示在当前工作路径下打开文件。(进程中存在当前工作路径cwd
)
标志位flags
通过查看open
函数说明可以看到,flags
存在非常多的标志位;这里列举一些常用的选项
O_RDONLY
只读、O_WRONLY
只写、O_RDWR
读写;
O_CREAT
:文件不存在时就新建文件
O_TRUNC
:打开文件时,文件存在就清空文件内容
O_APPEND
:打开文件时,以追加形式打开。
这里flags
表示的就是文件的打开方式;
首先就是:只读、只写和读写;在我们打开文件时必须指定一个且只能指定一个。
O_CREAT
在我们打开一个文件时,如果这个文件不存在,那open
函数就会直接返回-1
表示文件打开失败;
而我们带了O_CREAT
选项,就表明当文件不存在时,就新建文件;(这里新建文件要指明新建文件的权限,否则创建出来文件的权限就是乱码)
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{ int fd = open("love.txt",O_CREAT | O_WRONLY,0666); if(fd < 0){ perror("open"); return 1; } return 0;
}
一般情况下,在以写方式打开文件,文件不存在就新建,就要指明文件的权限。
(以只读读方式
O_RDONLY
,文件不存在新建出的文件是空的,没有什么意义)
O_TRUNC
当我们打开一个文件时,如果这个文件已经存在了,那就打开这个已有的文件;
如果我们带了O_TRUNC
选项,就表示清空这个文件的内容;
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{ int fd = open("love.txt",O_CREAT | O_WRONLY | O_TRUNC,0666); if(fd < 0){ perror("open"); return 1; } return 0;
}
O_APPEND
在C语言的文件操作中,fopen
打开文件,w
就是以写方式打开、文件不存在就新建、文件存在就清空文件的内容;(这就对应了上述选项的O_WRONLY
、O_CREAT
、O_TRUNC
)
但是我们fopen
还可以以a
方式打开文件,也就是追加方式;这里的O_APPEND
就是以追加的方式打开文件。
这里我们先看一种现象:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{ int fd = open("love.txt",O_CREAT | O_WRONLY,0666); if(fd < 0){ perror("open"); return 1; }char buff[] = "abcdef";write(fd,buff,strlen(buff)); return 0;
}
可以看到,我们不带
O_APPEND
选项,写入的时候是在文件的开头位置进行写入的。
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{ int fd = open("love.txt",O_CREAT | O_WRONLY | O_APPEND,0666); if(fd < 0){ perror("open"); return 1; }char buff[] = "abcdef";write(fd,buff,strlen(buff)); return 0;
}
文件权限mode
当打开文件,文件不存在,我们还带了O_CREAT
选项时;如果我们不带文件的权限,那新建文件的权限就是乱码;
而新建的文件的权限:文件权限 = 默认权限 &(~umask)
3. 关闭文件
关闭文件的系统调用close
,根据文件描述符,关闭指定文件。
对于这里的
fd
,它指的是文件描述符,当我们打开文件成功时,会返回给我们该文件的文件描述符;我们对指定文件的读写操作,以及关闭文件都要使用指定文件的文件描述符。
4. 文件写入write
在C语言中,我们进行文件写入时,我们有非常多的接口;
但是在系统层面,我们对文件进行写入只有一个接口,就是write
。
write
有三个参数,分别是fd
、buf
、和count
;
其中
fd
指的是文件描述符,表示我们要向哪一个文件进行写入;
buf
表示我们要进行写入的内容,它是void*
类型的指针,可以写入任何数据
count
就表示,我们要写入内容的长度。
这里值的注意的是:这里write
主要用于字符写入
当然,我们之前听过文本写入和二进制写入,那都是语言层的概念;
再这里我们操作系统不管这些,
write
就将给定的内容写入到文件缓冲区中。
5. 文件读取read
和写入一样,在语言层我们有非常多的函数接口,但是在系统层面,就只有read
。
这样存在三个参数;
fd
文件描述符,表示要从哪一个文件读取数据;
buf
,表示我们要将文件中的数据读取到buf
中;
count
表示要读取内容的长度。
文件描述符
在上面描述中,我们了解了文件操作相关的系统调用;
在open
、write
、read
、close
这些系统调用中,都用到了一个fd
来指明一个文件;那这个fd
究竟是什么呢?
open
函数的返回值
在上述使用open
函数时,我们并没有关心open
函数的返回值,也没有说明文件描述符到底是什么?
当我们使用
open
打开一个文件时:如果打开成功,那就返回这个新打开文件的文件描述符;
如果打开失败,就返回
-1
,并且设置错误码。
什么是文件描述符
那我们知道了,文件描述符就是标识一个文件的整数,每一个文件的文件描述符都不一样;
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{ int fd = open("log.txt",O_CREAT | O_WRONLY | O_APPEND,0666);if(fd < 0) return -1;printf("fd : %d\n",fd);close(fd);return 0;
}
我们可以看到打开的一个文件的文件描述符是3
;
这里打开一个文件我们看不出来什么,我们多打开一些文件
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{ int fd1 = open("log1.txt",O_CREAT | O_WRONLY | O_APPEND,0666);int fd2 = open("log2.txt",O_CREAT | O_WRONLY | O_APPEND,0666);int fd3 = open("log3.txt",O_CREAT | O_WRONLY | O_APPEND,0666);int fd4 = open("log4.txt",O_CREAT | O_WRONLY | O_APPEND,0666);//这里就不做错误判断了printf("fd1 : %d\n",fd1);printf("fd2 : %d\n",fd2);printf("fd3 : %d\n",fd3);printf("fd4 : %d\n",fd4);//不关闭文件,进程结束会自动关闭return 0;
}
这里,我们可以发现我们打开多个文件,这些文件的文件描述符是线性增长的。
文件描述符0/1/2
在上述中,我们发现,我们的文件描述符它是线性增长的,而且我们打开第一个文件它的文件描述符是3
;
那0
、1
、2
文件描述符去哪里了呢?
还记得在程序运行时,
C
语言会默认给我们打开三个文件stdin
、stdout
和strerr
;在
Linux
操作系统中,进程默认情况下会有三个缺省打开的文件描述符(0
、1
、2
),分别是标准输入、标准输出和标准错误。那这里进程默认打开的标准输入、标准输出和标准错误和C语言中的
stdin
、stdout
和stderr
有什么区别呢?
这里0
标准输入、1
标准输出、2
标准错误;
一般情况下0,1,2
对应的物理设备是键盘、显示器、显示器。
所以,我们从键盘中读取数据就是从0
文件中读取数据;将数据输出到显示器中就是将数据输出到1
文件当中。
文件描述符的分配规则
当我们打开一个文件时,它的文件描述符是3
;我们打开多个文件时,我们可以发现它的文件描述符是线性增长的;
那文件描述符是如何分配的呢?是一直在增长的吗?
#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("log1.txt",O_CREAT | O_WRONLY | O_TRUNC, 0666 ); if(fd1 < 0) return -1; printf("fd1 : %d\n",fd1); close(0); close(2); int fd2 = open("log2.txt",O_CREAT | O_WRONLY | O_TRUNC, 0666 ); if(fd2 < 0) return -1; printf("fd2 : %d\n",fd2); int fd3 = open("log3.txt",O_CREAT | O_WRONLY | O_TRUNC, 0666 ); if(fd3 < 0) return -1; printf("fd3 : %d\n",fd3);return 0;
}
可以看到,我们关闭
0
、2
文件之后,新打开文件的文件描述符是0
和2
所以,这里我们文件描述符分配时,会从0
开始去找到一个最小且没有被使用的文件描述符,再进行分配。
操作系统对于打开的文件的管理
对于上面的文件描述符,可以说很抽象,为什么可以使用一个整数来表示一个打开的文件呢?
现在来看操作系统是如何对被打开的文件进行管理的。
要想进行管理,那一定是先描述,再组织
**先描述:**操作系统要像对被打开文件进行管理,那就要先描述这些被打开文件;在Linux
操作系统中就存在struct file
结构体来描述这些被打开的文件(struct file
里就可能有文件描述符等等一些关于文件的信息)。
所以,在打开一个文件时,就只需根据文件的相关属性构建相对应的
struct file
即可(还存在文件缓冲区,也会将部分内容拷贝到文件缓冲区中)
再组织: 操作系统要将这些被打开文件(struct file
)进行管理;在Linux
操作系统中就存在一个全局链表,所以被打开文件的struct file
都在这个链表当中。
这样操作系统就将所有被打开的文件管理起来的,但是现在还有一个问题,程序打开文件也就是进程要打开文件,那进程是如何打开的呢?
这个问题就比较简单了,我们的进程不是有对应的task_struct
吗,那我们进程打开了哪些文件就肯定在tasj_struct
中存储着相对应的信息。
在
task_struct
中,存在着一个指针struct file_struct* files
,这个指针指向进程相对应的文件描述符表
;而在
文件描述符表
中,存在着一个数组struct file* fd_array
;而我们的文件描述符就和这个
fd_array
数组的下标一一对应。
那么,也就是说我们文件描述符表在的fd_array
数组,下标0
、1
…和我们文件描述符一一对应。
那么,在进程执行的过程中,只需要访问
task_struct
中的文件描述符表中的fd_array
数组,就可以知道我们进程打开了哪些文件。
了解了操作系统对于被打开文件的管理,现在再来看文件描述符
它就是进程文件描述符表中
fd_array
的数组下标;在新建文件时,操作系统就会遍历进程的描述符表中
fd_array
数组,找到一个最小且没有被使用的数组下标来作为新打开文件的文件描述符。
stdin/stdout/stderr
和文件描述符0/1/2
的区别
我们知道,在C
语言程序启动时,它会默认打开三个文件stdin/stdout/stderr
,这是语言层面的概念;
而文件描述符0/1/2
这是操作系统层面的概念。
在C语言中stdin/stdout/stderr
的类型都是FILE*
,我们只知道FILE*
是文件类型的指针,但是FILE
它是什么呢?
其他的我们不懂,但是这里我们可以肯定在FILE
中肯定存在文件对应的文件描述符;(因为C语言文件操作是封装了系统调用,而系统调用是使用文件描述符来访问文件的,所以在FILE
肯定存在文件所对应的文件描述符)
并且我们也可以确定,stdin
对应的文件描述符肯定是0
、stdout
对应的文件描述符肯定是1
、stderr
对应的文件描述符肯定是2
。
这里提出一个问题?
我们知道文件描述符的分配规则是找一个最小且没有被使用的文件描述符进行分配。
那如果我们关闭了
0/1/2
文件,再创建文件那0/1/2
还是标准输入、标准输出和标准错误吗?
答案是的,在语言层我们标准输入stdin
中的文件描述符就是0
、标准输出stdout
中的文件描述符就是1
、标准错误stderr
中的文件描述符就是2
。
我们关闭
0/1/2
文件,这一操作是系统层的操作,我们语言层C
它并不知道;那也就是说,在程序往标准输出中输出数据时,它只会拿着
stdout
中的文件描述符1
去调用系统调用;那也就是说在系统层:文件描述符
0
指向哪个文件,哪个文件就是标准输入;文件描述符1
指向哪个文件,哪个文件就是标准输出;文件描述符2
指向哪个文件,哪个文件就是标准错误。
本篇文章到这里就结束了,感谢各位的支持。
继续加油!!!
相关文章:
深入了解linux系统—— 基础IO(上)
文件 在之前学习C语言文件操作时,我们了解过什么是文件,这里简单回顾一下: 文件存在磁盘中,文件有分为程序文件、数据文件;二进制文件和文本文件等。 详细描述见文章:文件操作——C语言 文件在磁盘里&a…...
C++ map multimap 容器:赋值、排序、大小与删除操作
概述 map和multimap是C STL中的关联容器,它们存储的是键值对(key-value pairs),并且会根据键(key)自动排序。两者的主要区别在于: map不允许重复的键multimap允许重复的键 本文将详细解析示例代码中涉及的map操作,包括赋值、排…...
EmuEdit
EmuEdit详解:统一多任务图像编辑的扩展性范式 引言:图像编辑的困境 近年来,扩散模型(Diffusion Models)在图像合成和编辑方面取得了巨大进展,如 Prompt-to-Prompt (P2P)、InstructPix2Pix、DiffEdit 等方法…...
Linux编译rpm包与deb包
注意: 本文内容于 2025-05-14 23:55:53 创建,可能不会在此平台上进行更新。如果您希望查看最新版本或更多相关内容,请访问原文地址:编译rpm包与deb包。感谢您的关注与支持! 近期在通过源码编译安装一些软件包时&#…...
GitHub 趋势日报 (2025年05月17日)
本日报由 TrendForge 系统生成 https://trendforge.devlive.org/ 🌐 本日报中的项目描述已自动翻译为中文 📈 今日整体趋势 Top 10 排名项目名称项目描述今日获星总星数语言1TapXWorld/ChinaTextbookPDF教材。⭐ 2471⭐ 22302Roff2public-apis/public-a…...
[创业之路-362]:企业战略管理案例分析-3-战略制定-华为使命、愿景、价值观的演变过程
一、华为使命、愿景、价值观的演变过程 1、创业初期(1987 - 1994 年):生存导向,文化萌芽 使命愿景雏形:1994年华为提出“10年之后,世界通信行业三分天下,华为将占一份”的宏伟梦想,…...
Android 性能优化入门(二)—— 内存优化
1、概述 1.1 Java 对象的生命周期 各状态含义: 创建:分配内存空间并调用构造方法应用:使用中,处于被强引用持有(至少一个)的状态不可见:不被强引用持有,应用程序已经不再使用该对象…...
(5)python爬虫--BeautifulSoup(bs4)
文章目录 [TOC](文章目录) 前言一、安装bs4二、bs4的基础使用2.1 创建soup对象2.2 根据标签名查找节点2.3 根据函数来查找节点1. find函数2. find_all函数3. select函数 三、使用bs4获取节点信息3.1 获取节点内容3.2 获取节点的属性3.3 获取节点的属性值 四、测试练习 总结 前言…...
如何利用DeepSeek提升工作效率
1. 代码开发辅助 1.1 代码生成 根据需求描述生成代码框架 自动补全代码片段 生成单元测试用例 创建项目文档 1.2 代码优化 代码重构建议 性能优化方案 最佳实践推荐 设计模式应用 2. 问题诊断与解决 2.1 错误分析 编译错误解析 运行时错误诊断 内存泄漏检测 性…...
游戏引擎学习第292天:实现蛇
每次VLC 读取OSD 会有bug 修复一下 回顾并计划实现一种漂浮的移动方式,并制作一个贪吃蛇 虽然不完全记得之前具体计划,但感觉是想实现一个小蛇形生物,之前一直没来得及做。我们还打算让熟悉的伙伴能漂浮移动,所以今天会继续进行一…...
菱形继承原理
在C中,菱形继承的内存模型会因是否使用虚继承产生本质差异。我们通过具体示例说明两种场景的区别: 一、普通菱形继承的内存模型 class A { int a; }; class B : public A { int b; }; class C : public A { int c; }; class D : public B, public C { i…...
C++编程起步项目
员工信息管理系统 需求 Employee.h #pragma once#include<iostream> #include<string>using namespace std;class Employee { public:int id; // 编号string name; // 姓名string position; // 岗位int deptId; // 部门编号Employee();Employee(int id, string n…...
c++编写中遇见的错误
目录 一.获取动态数组的长度二.编译错误三、内存泄露 一.获取动态数组的长度 首先想到获取数组的长度的代码是: sizeof(arr) / sizeof(arr[0]);但是当将其使用到动态数组上时就会产生错误; int* help new int[3];for (int i 0; i < 3; i) {help[…...
股票数据源对接技术指南:印度尼西亚、印度、韩国
一、多国数据对接全景图 1. 核心数据领域对比 国家金融市场数据源宏观经济指标特色数据资源印度NSE/BSE实时行情RBI经济统计库UPI支付数据/GST税务记录印尼IDX交易所数据流BPS官方统计棕榈油产业数据/群岛物流信息韩国KRX综合指数KOSTAT国家统计K-POP消费趋势/半导体出口数据…...
常见面试题:Webpack的构建流程简单说一下。
文章目录 前言一、Webpack 的核心使命:模块化打包二、Webpack 构建流程详解三、构建流程的可视化演示项目结构构建流程图 四、构建流程中的关键技术点1. 依赖图的构建与优化2. 哈希与缓存策略3. 开发环境优化 五、简易版概括构建流程 总结 前言 在前端工程化中&…...
Elasticsearch基础篇-java程序通过RestClient操作es
目录 1.引入 2 初始化RestClient 1)引入es的RestHighLevelClient依赖: 2)因为SpringBoot默认的ES版本是7.17.10,所以我们需要覆盖默认的ES版本: 3)初始化RestHighLevelClient: 4)…...
SuperYOLO:多模态遥感图像中的超分辨率辅助目标检测之论文阅读
摘要 在遥感影像(RSI)中,准确且及时地检测包含数十像素的多尺度小目标仍具有挑战性。现有大多数方法主要通过设计复杂的深度神经网络来学习目标与背景的区分特征,常导致计算量过大。本文提出一种兼顾检测精度与计算代价的快速准确…...
k6学习k6学习k6学习k6学习k6学习k6学习
1.安装go 2.安装 xk6 (k6 扩展构建工具): go install go.k6.io/xk6/cmd/xk6latest3.构建自定义 k6 二进制文件(集成 faker 扩展): xk6 build --with github.com/gkarthiks/xk6-fakerlatest构建报错处理(代码拉取失败)࿱…...
ubuntu 安装mq
一、安装依赖 编译 Erlang 需要以下依赖库和工具: sudo apt update sudo apt install -y build-essential autoconf libncurses5-dev libssl-dev m4 unixodbc-dev libwxgtk3.0-gtk3-dev libgl1-mesa-dev libglu1-mesa-dev 二、解压源码包 tar -xzvf otp_src_21.…...
优化 Spring Boot 应用启动性能的实践指南
1. 引言 Spring Boot 以其“开箱即用”的特性深受开发者喜爱,但随着项目复杂度的增加,应用的启动时间也可能会变得较长。对于云原生、Serverless 等场景而言,快速启动是一个非常关键的指标。 2. 分析启动过程 2.1 启动阶段概述 Spring Boot 的启动流程主要包括以下几个阶…...
ubuntu18.04编译qt5.14.2源码
ubuntu18.04编译qt5.14.2源码 文章目录 ubuntu18.04编译qt5.14.2源码[toc]1 前言2 参考文档3 下载源码3.1 方法13.2 方法23.3 方法3 4 ubuntu编译qt源码4.1 环境准备4.2 设置交换分区大小4.3 编译源码4.4 添加环境变量4.5 验证编译结果4.6 编译帮助文档(qch…...
leetcodehot100刷题——排序算法总结
排序算法总结 冒泡排序介绍步骤(以升序排序为例)算法实现复杂度分析时间复杂度空间复杂度 是否为稳定排序:是稳定排序的定义 选择排序介绍步骤(以升序排序为例)算法实现复杂度分析时间复杂度空间复杂度 是否为稳定排序…...
多用途商务,电子产品发布,科技架构,智能手表交互等发布PPT模版20套一组分享
产品发布类PPT模版20套一组:产品发布PPT模版https://pan.quark.cn/s/25c8517b0be3 第一套PPT模版是一个总结用的PPT封面,背景浅灰色,有绿色叶片和花朵装饰,深绿色标题,多个适用场景和占位符。突出其清新自然的设计和商…...
2025年- H29-Lc137- 19.删除链表的倒数第N个节点(快慢指针)---java版
1.题目描述 2.思路 快慢指针都在虚拟头节点,然后让快指针先走n1步,接下来,快慢指针以前移动,直到快指针指向null,慢指针指向被删节点的前一个节点。 3.代码实现 方法一:不带测试用例 /*** Definition …...
新电脑软件配置二:安装python,git, pycharm
安装python 地址 https://www.python.org/downloads/ 不是很懂为什么这么多版本 安装windows64位的 这里我是凭自己感觉装的了 然后cmd输入命令没有生效,先重启下? 重启之后再次验证 环境是成功的 之前是输入的python -version 命令输入错误 安装pyc…...
医学影像开发的开源生态与技术实践:从DCMTK到DICOMweb的全面探索
🧑 博主简介:CSDN博客专家、CSDN平台优质创作者,高级开发工程师,数学专业,10年以上C/C++, C#, Java等多种编程语言开发经验,拥有高级工程师证书;擅长C/C++、C#等开发语言,熟悉Java常用开发技术,能熟练应用常用数据库SQL server,Oracle,mysql,postgresql等进行开发应用…...
【HarmonyOS 5开发入门】DevEco Studio安装配置完全指南
⭐本期内容:【HarmonyOS4+NEXT】Button组件核心特性 🏆系列专栏:鸿蒙HarmonyOS:探索未来智能生态新纪元 文章目录 前言下载开发工具安装开发工具配置开发环境新建项目项目结构概述运行项目Preview预览模拟器运行 报错处…...
出现 Uncaught ReferenceError: process is not defined 错误
在浏览器环境中,process 对象是 Node.js 环境特有的,因此当你在浏览器中运行代码时,会出现 Uncaught ReferenceError: process is not defined 错误。这个错误是因为代码里使用了 process.env.BASE_URL,而浏览器环境下并没有 proc…...
如何实现RTSP和RTMP低至100-200ms的延迟:直播SDK的技术突破
在实时音视频传输中,低延迟是直播应用的核心技术要求之一。无论是在线教育、远程医疗,还是实时互动直播,延迟过大会影响用户体验,甚至导致应用无法正常使用。大牛直播SDK(SmartMediaKit)在RTSP和RTMP播放器…...
linux-----------------库制作与原理(下)
1.ELF文件 要理解编译链链接的细节,我们不得不了解⼀下ELF⽂件。其实有以下四种⽂件其实都是ELF⽂件: • 可重定位⽂件(Relocatable File ) :即 xxx.o ⽂件。包含适合于与其他⽬标⽂件链接来创 建可执⾏⽂件或者共享…...
一种开源的高斯泼溅实现库——gsplat: An Open-Source Library for Gaussian Splatting
一种开源的高斯泼溅实现库——gsplat: An Open-Source Library for Gaussian Splatting 文章目录 一种开源的高斯泼溅实现库——gsplat: An Open-Source Library for Gaussian Splatting摘要Abstract1. 基本思想1.1 设计1.2 特点 2. Nerfstudio&Splatfacto2.1 Nerfstudio2.…...
Embedding 模型详解:架构、训练与 LLM 的区别
1. 什么是 Embedding 模型? Embedding 模型的核心使命是将离散的、高维的文本数据(例如单个词语、短语、句子、段落乃至整篇文档)转化为稠密的 (dense)、低维的 (low-dimensional)、连续的 (continuous) 向量表示。这些向量被称作“嵌入 (Em…...
网络的知识的一些概念
1.什么是局域网,什么是广域网 局域网(Local area network)也可以称为本地网,内网,局域网有这几个发展经历: 最开始电脑与电之间是直接用网线连接的 再后来有了集线器() 再后来出…...
NAT(网络地址转换)逻辑图解+实验详解
原理 NAT(Network Address Translation,网络地址转换) 是一种网络技术,用于在IP数据包通过路由器或防火墙时,修改其源IP地址或目标IP地址,以实现不同网络之间的通信。 基础概念 本来NAT是来解决 IPv4 地…...
深入解析Spring Boot与Kafka集成:构建高性能消息驱动应用
深入解析Spring Boot与Kafka集成:构建高性能消息驱动应用 引言 在现代分布式系统中,消息队列是实现异步通信和解耦的重要组件。Apache Kafka作为一种高性能、分布式的消息系统,被广泛应用于大数据和实时数据处理场景。本文将详细介绍如何在…...
Linux的内存泄漏问题及排查方法
内存泄漏是指在计算机程序中,已不再被使用的内存未被正确释放,导致内存占用随时间累积,进而引发系统内存不足、性能下降甚至崩溃的问题。在Linux系统中,开发者和运维人员可通过以下方法排查和解决内存泄漏问题: 1. 使…...
Java基础知识总结(超详细整理)
一:概述 1.1Java类及类的成员 属性、方法、构造器、代码块、内部类 (1)数组 java虚拟机内存划分 各区域作用 内存解析 基本使用 两个变量指向一个一维数组 没有new就不会在堆里新开辟空间 (2)对象数组 (3&a…...
Qt Widgets模块功能详细说明,基本控件:QPushButton(二)
一、基本控件(Widgets) Qt 提供了丰富的基本控件,如按钮、标签、文本框、复选框、单选按钮、列表框、组合框、菜单、工具栏等。 1、QPushButton 1.1、概述 (用途、继承关系) QPushButton 是 Qt 框架中用于创建按钮的控件,它的主…...
【MySQL成神之路】MySQL常见命令汇总
目录 MySQL常用命令总结 1. 数据库操作 2. 表操作 3. 数据操作(DML) 4. 索引与优化 5. 用户与权限管理 6. 备份与恢复 7. 事务控制 8. 常用函数 9. 系统状态与日志 总结 MySQL常用命令总结 MySQL作为最流行的关系型数据库之一,提供…...
UnLua源码分析(一)初始化流程
UnLua源码分析(一)初始化流程 接入插件启动注册设置默认参数集注册回调SetActivePostLoadMapWithWorldULuaEnvLocator启动Lua虚拟机初始化UE相关的Lua Lib创建与Lua交互的数据结构注册静态导出的类,函数,枚举Lua层初始化 UUnLuaMa…...
非线性1 修改
第一章为读者介绍了非线性动力学与混沌理论的基本概念、发展历史以及应用领域。 1.1 动力学简史: 从牛顿力学开始,介绍动力学作为物理学分支的发展历程。重点介绍了庞加莱对混沌现象的早期探索,以及20世纪60年代洛伦兹方程的发现࿰…...
系统性能不达标,如何提升用户体验?
当系统性能不达标时,要想有效提升用户体验,必须从性能优化、前后端协同、用户感知改善、监控预警机制四个关键维度切入。其中,性能优化是最直接有效的策略,它通过代码优化、资源压缩、缓存机制、CDN加速等手段,显著提升…...
【Linux】进程的基本概念
目录 概念描述进程-PCB如何查看进程通过系统目录进行查看通过ps指令进行查看 通过系统调用获取进程的PID和PPID(进程标⽰符)通过系统调用创建子进程通过一段代码来介绍fork为什么要有子进程?fork为什么给子进程返回0,给父进程返回子进程的PIDfork函数到底…...
mongodb管理工具的使用
环境: 远程服务器的操作系统:centOS stream 9; mongoDB version:8.0; 本地电脑 navicat premium 17.2 ; 宝塔上安装了mongoDB 目的:通过本地的navicat链接mongoDB,如何打通链接,分2步: 第一步:宝塔-&…...
面试中的线程题
原文链接:线程题大全 Java 并发库同步辅助类 CountDownLatch 工作机制:初始化一个计数器,此计数器的值表示需要等待的事件数量。 提供了两个主要方法: await():当一个线程调用此方法时,它将阻塞&#…...
计算机系统的层次结构
计算机系统的层次结构 一, 计算机系统的层次结构的定义 计算机的一个赢软件组成的综合体. 因为面对的应用范围越来越广, 所以必须有复杂的系统软件和硬件的支持. 软/硬件的设计者和使用者从不同的角度, 不同的语言来对待同一个计算机系统, 因此他们看到的计算机系统的属性对计…...
[特殊字符] SSL/TLS 中的密钥协商流程笔记
✅ 背景说明: SSL/TLS 为了确保通信保密性,结合使用了: 非对称加密(用于密钥交换) 对称加密(用于数据加密) 🔁 客户端主导密钥协商的完整流程如下: 1️⃣ 客户端发起…...
多模态大语言模型arxiv论文略读(八十一)
What is the Visual Cognition Gap between Humans and Multimodal LLMs? ➡️ 论文标题:What is the Visual Cognition Gap between Humans and Multimodal LLMs? ➡️ 论文作者:Xu Cao, Bolin Lai, Wenqian Ye, Yunsheng Ma, Joerg Heintz, Jintai …...
SpringBoot(一)--- Maven基础
目录 前言 一、初始Maven 1.依赖管理 2.项目构建 3.统一项目结构 二、IDEA集成Maven 1.Maven安装 2.创建Maven项目 2.1全局设置 2.2 创建SpringBoot项目 2.3 常见问题 三、单元测试 1.JUnit入门 2.断言 前言 Maven 是一款用于管理和构建Java项目的工具ÿ…...
如何使用WordPress创建美食博客
不管你是否意识到,食物是我们生活的核心。有些人将其用作燃料,而另一些人则将食谱作为一种艺术形式呈现。如果您属于后者,并且想创建一个美食博客来分享您的热情,那么WordPress是一个顶级平台。 几乎每个话题都有一个博客利基&am…...