【Linux】文件描述符——万字详解

news2025/1/17 22:01:03

目录​​​​​​​

前言

预备知识 

复习C语言的文件接口

写方式打开文件

追加方式打开文件

读方式打开文件

系统的文件接口

open

close 

write

read

文件描述符

0 & 1 & 2 

理解文件描述符

文件描述符的分配规则

重定向的本质

dup2

理解Linux下一切皆文件


前言

本篇文章内容有点多,但是非常的重要,,希望你可以坚持看下去,看会你将会对Linux下一切皆文件有一个全新的理解。

如果内容有错或者不足,还望你能指出,让我们共同进步

预备知识 

知识点1 

当我们创建了一个空文件时,这个空文件是否会占空间呢?

答案是:当然啦,因为文件 = 内容 + 属性,文件的属性也是数据当然会占空间啦

因此我们对文件的操作无外乎是对文件的内容或者文件的属性做操作。

知识点2

文件会被加载到磁盘中,我们在C语言或者其它语言中通过编写代码并运行来访问文件,那么这本质是谁在访问文件呢?

答:是进程通过C语言或者其它语言给我们提供的文件接口来访问的。

知识点3 

我们的磁盘是属于硬件,我们普通用户是没有权利向硬件中写入的,只有操作系统才有这个权利,而我们也想要向硬件中写入的话必须通过操作系统提供给我们的接口才能向磁盘中写入。

知识点4

显示器也是属于硬件,我们在C语言中使用printf向显示器中打印时,其实和向磁盘中写入是一样的,没有本质的区别。 

知识点5

所有的语言给我们都提供了有文件访问接口,其实在底层实现都封装的是系统调用的接口,那么这些语言为什么要封装其接口呢?

封装的原因是系统调用的接口比较难,为了能让这些接口更好的给用户使用,所以在语言层面上对这些接口进行了封装。并且这些语言为了实现跨平台性,在底层把所用平台提供的文件接口都实现了一遍,通过条件编译的方式将这些代码进行动态裁剪(就跟多态才不多),这样就能实现在不同平台调用的文件访问接口都是一样的。

知识点6

Linux下一切皆文件,在这里先有个感性的认识,站在你写代码的角度,你会认为加载到内存中的就是文件,但站在系统的角度,能够被读取或者能够被写入的设备就叫做文件。

狭义上理解的文件:普通的磁盘文件

广义上理解的文件:几乎所有外设都可被称为文件。

复习C语言的文件接口

文件打开的方式

写方式打开文件

 先来看看下面的代码

#include <stdio.h>

int main()
{
  FILE *fp = fopen("log.txt", "w");
  if(fp == NULL)
  {
    perror("fopen");
    return 1;
  }


  fclose(fp);
  return 0;
}

我们都知道当我们执行这份代码时,如果当前路径下没有log.txt文件,w方式会在当前路径下创建log.txt文件,那么什么叫做当前路径呢?

所以当前路径是指当你的进程运行起来时所处的工作路径

在来看看下面的代码

#include <stdio.h>
#include <string.h>

int main()
{
  FILE *fp = fopen("log.txt", "w");
  if(fp == NULL)
  {
    perror("fopen");
    return 1;
  }
  
  const char *s1 = "hello man\n";
  fwrite(s1, strlen(s1), 1, fp);


  fclose(fp);
  return 0;
}

我们知道字符串的末尾是会加上一个'\0',那么这里的strlen(s1)是否要加1呢?

答案肯定是不要的,因为'\0'结尾是C语言的规定,文件不需要遵守,并且文件中要保存的是有效数据,'\0'不是有效数据。如果你加上1的话就会出现以下乱码的情况。

当我们以w方式写入时,是先清空文件中的内容再写入。

把上个图片中的hello man和乱码清除再写入hello Linux

这个就和输出重定向很像

追加方式打开文件

#include <stdio.h>
#include <string.h>

int main()
{
  FILE *fp = fopen("log.txt", "a");
  if(fp == NULL)
  {
    perror("fopen");
    return 1;
  }
  
  const char *s1 = "hello Linux\n";
  fwrite(s1, strlen(s1), 1, fp);


  fclose(fp);
  return 0;
}

 

读方式打开文件

#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[])//命令行参数
{
  if(argc != 2)
  {
    printf("argv error");
    return 1;
  }
  FILE *fp = fopen(argv[1], "r");
  if(fp == NULL)
  {
    perror("fopen");
    return 2;
  }

  char line[64];
  while(fgets(line, sizeof(line), fp) != NULL)
  {
    fprintf(stdout, "%s", line);//向显示器输出
  }

  fclose(fp);
  return 0;
}

这样就实现了和cat一样的功能

在上面的代码中用到了一个stdout,这个stdout为标准输出

在C语言中会默认打开三个标准输入输出流:stdin、stdout、stderr

并且这三个流的类型都是FILE*的(解释在后面)

系统的文件接口

在上面已经说到了C语言标准库中给我们提供的文件操作的函数在底层其实是调用的系统提供的文件接口,那么系统给我们提供了哪些文件接口呢?下面让我们来认识一下这些文件接口

open

打开成功返回的是一个文件描述符,失败则返回-1

参数介绍

pathname:要打开的目标文件

flags:打开文件的方式。提供了多个选项,可传入多个选项共同构成这个参数

下面三个选项必须指定一个且只能指定一个

  • O_RDONLY:只读
  • O_WRONLY:只写
  • O_RDWR:可读可写

上面选项配合其它选项一起使用,如

  • O_APPEND 表示追加方式的写入文件
  • O_CREAT 表示如果指定文件不存在,则创建这个文件
  • O_TRUNC 表示截断,如果文件存在,并且以只写、读写方式打开,则将其长度截断为0。
  • ……

这些选项还有好多这里就不一一列举了,大家可以通过man进行查看

可以观察到这些选项都是大写,一般这种大写的基本上是宏定义,这里也不例外。

我们通过或(|)运算就可以将这些选项结合在一起使用了,例如:O_WRONLY|O_CREAT

为什么使用或运算就可以将这些选项结合在一起使用了呢?

其实这里是用到了一个位图的思想,看了下面代码想必你应该就会明白了

#include <stdio.h>
#include <string.h>

//用不重复的位就可以标识一个状态
#define ONE 0x1 //0000 0001
#define TWO 0x2 //0000 0010
#define THREE 0x4 //0000 0100

void print(int flags)
{
  //&运算:有0则为0,全1才为1
  if(flags & ONE) printf("I am ONE\n");
  if(flags & TWO) printf("I am TWO\n");
  if(flags & THREE) printf("I am THREE\n");
}

int main()
{
  print(ONE);
  printf("--------------------------------\n");
  print(TWO);
  printf("--------------------------------\n");
  print(THREE);
  printf("--------------------------------\n");
  print(ONE | TWO | THREE);//0000 0001 | 0000 0010 | 0000 0100 = 0000 0111
  printf("--------------------------------\n");
  print(ONE | TWO);//0000 0001 | 0000 0010 = 0000 0011
  printf("--------------------------------\n");
  print(ONE | THREE);//0000 0001 | 0000 0100 = 0000 0101
  printf("--------------------------------\n");
  return 0;
}

库中也确实是这样干的

mode:为设置文件访问的权限

红色区域即为文件的权限,新建文件夹的默认权限是0666,但实际看到的权限不是这个值,因为还会受到umask的影响,umask默认是0002

使用

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main()
{
  int fd = open("log.txt", O_WRONLY|O_CREAT|O_TRUNC, 0666);
  if(fd < 0)
  {
    perror("open");
    return 1;
  }

  printf("open success, fd:%d\n", fd);

  return 0;
}

close 

关闭一个文件描述符,成功返回0,失败返回-1并且设置对应的错误码

和fclose的用法就差不多

write

返回值为实际写入的有效数据,ssize_t为有符号整形

参数介绍

fd:为文件描述符

buf:为要写入的数据

count:为写入数据的大小

使用演示

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

int main()
{
  int fd = open("log.txt", O_WRONLY|O_CREAT|O_TRUNC, 0666);
  if(fd < 0)
  {
    perror("open");
    return 1;
  }

  printf("open success, fd:%d\n", fd);

  const char *s1 = "hello write\n";
  write(fd, s1, strlen(s1));
    
  close(fd);
  return 0;
}

 

read

 

返回值的读取到的有效数据 

参数和write一样就不过多介绍了

使用演示

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

int main()
{
  int fd = open("log.txt", O_RDONLY);
  if(fd < 0)
  {
    perror("open");
    return 1;
  }

  printf("open success, fd:%d\n", fd);
  
  char buffer[64];
  memset(buffer, '\0', sizeof(buffer));
  read(fd, buffer, sizeof(buffer));
  printf("%s\n", buffer);
  
  close(fd);
  return 0;
}

这里系统接口可不会给我们在末尾加上\0,所以我们需要手动在末尾加上'\0'。 

文件描述符

0 & 1 & 2 

先来看一下下面的代码 

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

int main()
{
  int fd1 = open("log1.txt", O_WRONLY|O_CREAT);
  int fd2 = open("log2.txt", O_WRONLY|O_CREAT);
  int fd3 = open("log3.txt", O_WRONLY|O_CREAT);
  int fd4 = open("log4.txt", O_WRONLY|O_CREAT);

  printf("open success, fd1:%d\n", fd1);
  printf("open success, fd2:%d\n", fd2);
  printf("open success, fd3:%d\n", fd3);
  printf("open success, fd4:%d\n", fd4);
    
  close(fd1);
  close(fd2);
  close(fd3);
  close(fd4);
  return 0;
}

从上面的的代码可以看出fd都是从3开始的,那么前面的0,1,2去哪里了呢

在上面复习C语言文件接口时,提到过C语言中会默认打开三个标准输入输出流:stdin、stdout、stderr,这三个标准的输入输出流对应的就是0,1,2。

不信的话我们可以验证一下

stdout 

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

int main()
{
  fprintf(stdout, "hello stdout\n");
  const char *s1 = "hello 1\n";
  write(1, s1, strlen(s1));
  return 0;
}

stdin 

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

int main()
{
  char buf[64];
  ssize_t s = read(0, buf, sizeof(buf));
  if(s > 0)
  {
    buf[s] = '\0';//在读取到的有效数据的末尾添加\0
    printf("%s\n",buf);
  }

  return 0;
}

我们再回到C语言中,我们在使用C语言的文件函数时都见过FILE*,这个FILE*是一个指针,那么这个FILE是什么呢?

FILE其实是一个结构体,是C语言对底层做出的一个封装,里面包含了很多成员其中就有这个fd(文件描述符)。

#include <stdio.h>

int main()
{
  printf("stdin:%d\n", stdin->_fileno);
  printf("stdout:%d\n", stdout->_fileno);
  printf("stderr:%d\n", stderr->_fileno);

  return 0;
}

理解文件描述符

进程要访问文件,必须先要打开文件,并且一个进程可以打开多个文件,那么如果多个进程都打开自己的文件,系统中就会存在大量被打开的文件,面对如此之多的文件,操作系统肯定要管理起来,而管理的本质就是先描述,再组织。所以在操作系统的内部为了管理每一个被打开的文件,会构建一个结构体,这个结构体中包含了一个被打开的文件的所有内容,然后再将这一个个的结构体用双链表组织起来。

当我们调用open时,必须让进程和文件关联起来,才能打开对应文件,那么我们的进程又是如何和文件关联起来的呢?

在每个进程的PCB中都有一个指针*files,指向一张表files_struct,该表中会包含一个指针数组,数组中的每个元素都是一个指向打开文件的指针,这就实现了和文件进行关联。

那么既然是数组就会有下标,并且是从0开始的,所以文件描述符的本质就是该指针数组的下标。所以只要拿着文件描述符,就可找到对应的文件。

文件描述符的分配规则

从上面的演示中我们就知道了0,1,2已经被三个标准输入输出流给占了,所以我们调用open打开文件时文件描述符(后面就简称fd了)只能从3以后开始,那么我们尝试close关闭0或者2看一下会发生什么现象?

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>


int main()
{
  //close(0);
  close(2);
  int fd = open("log.txt", O_WRONLY|O_CREAT|O_TRUNC, 0666);
  if(fd < 0)
  {
    perror("open");
    return 1;
  }

  printf("fd: %d\n", fd); 
  printf("fd: %d\n", fd); 
  printf("fd: %d\n", fd); 
  printf("fd: %d\n", fd); 
  printf("fd: %d\n", fd); 
  printf("fd: %d\n", fd); 
  close(fd);
  return 0;
}

所以fd的分配规则是:当前没有被使用的最小的一个下标

重定向的本质

当我们close关闭1又会发生什么现象呢?

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

int main()
{
  close(1);
  int fd = open("log.txt", O_WRONLY|O_CREAT, 0666);
  if(fd < 0)
  {
    perror("open");
    return 1;
  }

  printf("fd: %d\n", fd); 
  printf("fd: %d\n", fd); 
  printf("fd: %d\n", fd); 
  printf("fd: %d\n", fd); 
  printf("fd: %d\n", fd); 
  printf("fd: %d\n", fd);

  fflush(stdout);
  close(fd);
  return 0;
}

本该往显示器打印的内容结果打印到文件中去了。

这种现象是不是就和输出重定向是一样的了

本质

输入重定向

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>


int main()
{
  close(0);
  int fd = open("log.txt", O_RDONLY, 0666);
  if(fd < 0)
  {
    perror("open");
    return 1;
  }

  printf("fd: %d\n", fd); 
  char buffer[64];
  fgets(buffer, sizeof buffer, stdin);
  printf("%s\n", buffer);

  fflush(stdout);
  close(fd);
  return 0;
}

追加重定向

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>


int main()
{
  close(1);
  int fd = open("log.txt", O_WRONLY|O_CREAT|O_APPEND);
  if(fd < 0)
  {
    perror("open");
    return 1;
  }

  fprintf(stdout, "hello hjx\n");

  fflush(stdout);//刷新缓冲区
  close(fd);
  return 0;
}

但事实上重定向并不是这样实现的,我们上面的实现只是利用了fd的分配规则,而在操作系统中早就给我们准备了实现重定向的接口。

dup2

 

dup2的使用描述​​​​​​​

这里的意思就是将旧的文件描述符所对应的内容拷贝的新的文件描述符中,最后两个文件描述符是和旧的文件描述符保持一致,如果必要时把新的文件描述符关掉。

dup2的使用

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>


int main()
{
  int fd = open("log.txt", O_WRONLY|O_CREAT|O_APPEND, 0666);
  if(fd < 0)
  {
    perror("open");
    return 1;
  }
  dup2(fd, 1);
  fprintf(stdout, "hello dup2\n");

  close(fd);
  return 0;
}

理解Linux下一切皆文件

 Linux下一切皆文件时Linux的一个设计哲学,它是体现在操作系统的软件设计层面的。

我们都知道Linux是用C语言写的,那么你知道怎么用C语言来实现面向对象,甚至是运行时多态吗?

在C++或者其它语言中实现面向对象我们都知道是要用类,类中包含了成员属性和成员方法,但是C语言中只有结构体的概念,而结构体中只能包含成员属性,包含不了成员方法,那该怎么办呢?

没事,我们可以用到一个函数指针来实现其效果。

我们知道操作系统再往下就是硬件(比如磁盘、网卡、键盘、显示器等等)了,这些不同的硬件对应的一定是不同的驱动方法(你访问磁盘和访问键盘是不一样的),但是这些硬件都是外设,所以这每一个设备的核心驱动程序都可以是read/write——>I/O,根据冯诺依曼所有的外设无非都是I/O,所以所有的外设都可以有自己的read和write,但是代码实现一定是不一样的。

这种设计方案就叫做虚拟文件系统(VFS)。 

在Linux内核中也确实是这么干的。 

内核源码

 

struct file_operations {
	struct module *owner;
	loff_t (*llseek) (struct file *, loff_t, int);
	ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
	ssize_t (*aio_read) (struct kiocb *, char __user *, size_t, loff_t);
	ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
	ssize_t (*aio_write) (struct kiocb *, const char __user *, size_t, loff_t);
	int (*readdir) (struct file *, void *, filldir_t);
	unsigned int (*poll) (struct file *, struct poll_table_struct *);
	int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
	int (*mmap) (struct file *, struct vm_area_struct *);
	int (*open) (struct inode *, struct file *);
	int (*flush) (struct file *);
	int (*release) (struct inode *, struct file *);
	int (*fsync) (struct file *, struct dentry *, int datasync);
	int (*aio_fsync) (struct kiocb *, int datasync);
	int (*fasync) (int, struct file *, int);
	int (*lock) (struct file *, int, struct file_lock *);
	ssize_t (*readv) (struct file *, const struct iovec *, unsigned long, loff_t *);
	ssize_t (*writev) (struct file *, const struct iovec *, unsigned long, loff_t *);
	ssize_t (*sendfile) (struct file *, loff_t *, size_t, read_actor_t, void *);
	ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
	unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
	int (*check_flags)(int);
	int (*dir_notify)(struct file *filp, unsigned long arg);
	int (*flock) (struct file *, int, struct file_lock *);
};

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

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

相关文章

vue+springboot+websocket实时聊天通讯功能

前言 在我的前一篇文章里 vuespringboot实现聊天功能 &#x1f388;&#x1f388;&#x1f388;&#x1f388;&#x1f388;&#x1f388;&#x1f388; 实现了最最基础的聊天功能&#xff0c;可以通过聊天互相给对方发送信息 &#x1f388;&#x1f388;&#x1f388;&…

每日一题 — 最小覆盖子串

76. 最小覆盖子串 - 力扣&#xff08;LeetCode&#xff09; 解法一&#xff1a;暴力遍历哈希表 解法二&#xff1a;滑动窗口哈希表 定义left和right初始化为零&#xff0c;固定left&#xff0c;先向右遍历right&#xff0c;放到哈希表中这个时候我们需要统计有效字符的个数&…

企业智能EDM邮件群发推广软件哪个好?

精准、高效的电子邮件营销已经成为企业触达潜在客户、维护现有客户关系以及提升品牌影响力不可或缺的手段。在这其中&#xff0c;云衔科技以其独树一帜的智能EDM邮件营销系统解决方案&#xff0c;为企业带来了革命性的市场推广体验。 云衔科技凭借前瞻性的战略眼光和深厚的AI技…

抖音在线点赞任务发布接单运营平台PHP网站源码 多个支付通道+分级会员制度

抖音在线点赞任务发布接单运营平台PHP网站源码&#xff0c;多个支付通道分级会员制度。 介绍 1、代理裂变&#xff0c;静态返佣/动态返佣均可设置。 2、自动机器人做任务&#xff0c;任务时间可设置&#xff0c;机器人价格时间可设置。 3、后台可设置注册即送X天机器人。 …

RT-Thread在Win10下编译出现 unsupported pickle protocol: 5解决方案

调试背景&#xff1a; 在WIN10下编译RT-Thread源码&#xff1a;对象处理器平台是Microchip SAMA5D27-SOM1-EK评估板。 unsupported pickle protocol: 5 编译出现报错:ValueError : unsupported pickle protocol: 5 $ scons scons: Reading SConscript files ... Newlib ver…

c语言题目之求最大公约数

题目内容&#xff1a;求最大公约数 给定两个数&#xff0c;求这两个数的最大公约数 例如&#xff1a; 输入&#xff1a;20 40 输出&#xff1a;20 什么叫最大公约数&#xff1f; 方法分析&#xff1a; 提示&#xff1a;这里我们用辗转相除法&#xff1a; 例如&#xff1a;输…

七月论文审稿GPT第4.5版:通过15K条paper-review数据微调Llama2 70B(含各种坑)

前言 当我们3月下旬微调完Mixtral 8x7B之后(更多详见&#xff1a;七月论文大模型&#xff1a;含论文的审稿、阅读、写作、修订 )&#xff0c;下一个想微调的就是llama2 70B 因为之前积攒了不少微调代码和微调经验&#xff0c;所以3月底apple便通过5K的paper-review数据集成功…

Tensorflow2.0笔记 - 使用卷积神经网络层做CIFA100数据集训练(类VGG13)

本笔记记录CNN做CIFAR100数据集的训练相关内容&#xff0c;代码中使用了类似VGG13的网络结构&#xff0c;做了两个Sequetial&#xff08;CNN和全连接层&#xff09;&#xff0c;没有用Flatten层而是用reshape操作做CNN和全连接层的中转操作。由于网络层次较深&#xff0c;参数量…

鲁棒无监督人群计数与定位

鲁棒无监督人群计数与定位 摘要1 IntroductionMethod 摘要 现有的群体计数模型需要大量的训练数据&#xff0c;而这些数据的标注过程耗时且繁琐。为了解决这个问题&#xff0c;作者提出了一种简单而有效的人群计数方法&#xff0c;通过采用一种名为“Segment-Everything-Every…

高精度算法(1)

前言 今天来讲一讲高精度算法&#xff0c;我们说一个数据类型&#xff0c;有它的对应范围比如int类型最多 可以包含到负2的31次方到2的31次方减一 其实大概就是20亿左右那么其他的类型也同样如此 那么&#xff0c;如何解决一个很大很大的数的运算呢&#xff1f; 我们今天介…

gemini国内能用吗

gemini国内能用吗 虽然 Gemini 的具体功能和性能还未完全公开&#xff0c;但基于 Google 在 AI 领域的强大背景和技术实力&#xff0c;已经火出圈了&#xff0c;很多小伙伴已经迫不及待想了解一下它有什么优势以及如何快速使用上 首先我们来讲一下gemini的优势 多模态能力&a…

43、二叉树-验证二叉搜索树

思路&#xff1a; 有效 二叉搜索树定义如下&#xff1a; 节点的左子树只包含 小于 当前节点的数。节点的右子树只包含 大于 当前节点的数。所有左子树和右子树自身必须也是二叉搜索树。 所以对于当前节点来说&#xff1a;我的左节点要小于我&#xff0c;我的右节点要大于我&a…

顺序表详解(C语言实现)

顺序表介绍 顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构&#xff0c;一般情况下采用数组存 储。在数组上完成数据的增删查改。 顺序表一般可以分为&#xff1a; 1. 静态顺序表&#xff1a;使用定长数组存储元素。 2. 动态顺序表&#xff1a;使…

世界500强:破解“智慧核能”数智化成功转型密码

近日&#xff0c;实在智能携手中国核能行业协会信息化专业委员会在中国人工智能小镇成功举办“基于大模型的RPA数字员工在核能行业实战应用案例专项培训”&#xff0c;中国核工业集团、中国广核集团、国家电力投资集团等企事业单位共同参加。中核集团作为我国核科技工业的主体&…

screen常用命令

screen是一个在Linux系统中常用的命令行终端模拟器&#xff0c;它允许用户在一个单一终端会话中管理多个终端窗口。以下是一些常用的screen命令 1、创建一个新的screen会话并命名 screen -S <name>2、control a d &#xff1a;分离&#xff08;detach&#xff09;当前的…

TensorRT从入门到了解(2)-学习笔记

目录 1.TensorRT的高性能部署简介2.TensorRT驾驭方案3.如何正确导出onnx4.动态batch和动态宽高的实现5.实现一个自定义插件6.关于封装7.YoloV5案例8.Retinaface案例9.高性能低耦合10.YOLOX集成参考 1.TensorRT的高性能部署简介 tensorRT&#xff0c;nvidia发布的dnn推理引擎&a…

Kotlin语法快速入门--变量声明(1)

Kotlin语法入门–变量声明&#xff08;1&#xff09; 文章目录 Kotlin语法入门--变量声明&#xff08;1&#xff09;一、变量声明1、整型2、字符型3、集合3.1、创建array数组3.2、创建list集合3.3、不可变类型数组3.4、Set集合--不重复添加元素3.5、键值对集合Map 4、kotlin特有…

yolov8 区域计数

yolov8 区域计数 1. 基础2. 计数功能2.1 计数模块2.2 判断模块 3. 主代码4. 实验结果5. 源码 1. 基础 本项目是在 WindowsYOLOV8环境配置 的基础上实现的&#xff0c;测距原理可见上边文章 2. 计数功能 2.1 计数模块 在指定区域内计数模块 def count_objects_in_region(bo…

浅谈rDNS在IP情报建设中的应用

在当今数字化世界中&#xff0c;互联网已经成为人们日常生活和商业活动中不可或缺的一部分。在这个庞大而复杂的网络生态系统中&#xff0c;IP地址是连接和识别各种网络设备和服务的基础。然而&#xff0c;仅仅知道一个设备的IP地址并不足以充分理解其在网络中的角色和行为。为…

第四百六十七回

文章目录 1. 知识回顾2. 使用方法3. 示例代码4. 内容总结 我们在上一章回中介绍了"OverlayEntry组件简介"相关的内容&#xff0c;本章回中将介绍OverlayEntry组件的用法.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1. 知识回顾 我们在上一章回中介绍了Overlay…