linux系统基础知识-基础IO

news2024/11/15 10:22:19

IO

  • 概念引入
  • 位图的概念
  • IO的系统调用函数
    • open
    • write
    • read()
    • close
    • 简单使用样例:
  • 文件描述符fd
    • 默认文件流stdin/stdout/stderr
    • 文件描述符的分配规则
  • 重定向的概念
    • 输出重定向
    • 输入重定向
    • 追加重定向
    • dup2()系统调用
    • 总结
  • 文件缓冲区
    • 深入理解缓冲区的概念
    • 输出缓冲区部分代码解释
    • 总结
  • stdout和stderr的区别
    • 总结
    • 自己实现一个perror
  • 文件系统
    • inode
    • 发现系统还有空间,为什么不能创建文件?
  • 软硬链接

概念引入

在学习C语言的时候,我们学过一些文件操作的函数,比如fopen,fgets,fputs,fclose等等,其实这些函数的功能就是在操作文件,进行IO读取工作。这些是C语言封装的函数。
然而C语言封装的函数里面,一定有OS层面的动作,因为IO设计到硬件操作,而对于硬件的操作一定要通过系统调用,让OS帮助我们完成IO操作。
所以,为了更好的让大家理解IO原理,先介绍一下IO的系统调用接口。

位图的概念

在介绍系统调用函数之前,需要了解一下位图的概念。顾名思义就是每个比特位都有不通过的含义,代表着不同的功能。
下面使用一个例子介绍位图的应用:

  1 #include<stdio.h>
  2 
  3 
  4 // 用int中的不重复的一个bit,就可以标识一种状态
  5 // 第1个比特位表示功能一,第二个比特位表示功能二,第三个比特位表示功能三
  6 #define ONE 0x1   //0000 0001
  7 #define TWO 0x2   //0000 0010
  8 #define THREE 0x4 //0000 0100
  9 
 10 
 11 void show(int flags)
 12 {
 13   //哪个标志的比特位是1,就完成对应的功能
 14   if(flags & ONE) printf("功能ONE\n");
 15   if(flags & TWO) printf("功能TWO\n");
 16   if(flags & THREE) printf("功能THREE\n");
 17 }
 18 
 19 int main()
 20 {
 21   show(ONE);   //选择功能1
 22   show(TWO);    //选择功能2
 23   show(ONE | TWO);   //选择功能1和2
 24   show(ONE | TWO | THREE);  //选择功能123                                                                                                                           
 25   return 0;
 26 }

在这里插入图片描述

从上面的运行结果可以来看,我们使用位图的概念,实现了的方法可以选择任意功能。

IO的系统调用函数

open

类比fopen的使用,使用man 2 open查询open函数的用法。我们使用时,经常使用带mode的函数。
在这里插入图片描述

第一个参数:文件路径
第二个参数flags:功能位(位图的概念)
第三个参数:权限:可以使用16进制来表示,一般使用0x666表示rw权限。
返回值:成功时返回新打开的文件描述符。失败时:返回-1.

flags:打开文件时,可以传入多个参数选项,用下面的一个或多个常量进行"或"运算,构成flags。

  • O_RDONLY:只读打开
  • O_WRONLY:只写打开
  • O_RDWR:读、写打开 (上面这三个常量,必须写一个且只能写一个)
  • O_CREAT:若文件不存在,则创建它。需要使用mode选项,来指明文件的访问权限。
  • O_APPEND:追加写。

下面我们简单举个例子来打开文件:

  1 #include<stdio.h>
  2 #include<sys/types.h>
  3 #include<sys/stat.h>
  4 #include<fcntl.h>
  5 
  6 int main()
  7 {
  8   //只读并且没有文件创建。
  9   int fd = open("log.txt", O_WRONLY|O_CREAT, 0666);// rw-rw-rw                                                                                                      
 10   if(fd < 0)
 11   {
 12     perror("open:");
 13     return 1;
 14   }
 15 
 16   printf("打开成功, fd %d \n", fd);
 17 
 18   return 0;
 19 }

在这里插入图片描述

write

类比fwrite的使用,使用man 2 write查询open函数的用法。在这里插入图片描述

fd:文件描述符
buf:要写的字符串。
count:要写的大小(单位是字节)
返回值:ssize_t :实际写的有效字节数。

read()

类比fread。
在这里插入图片描述

将fd的功能读到字符串buf中,读取count个字节。

close

关闭指定文件,通过文件描述符关闭。
在这里插入图片描述

返回值:0代表成功。-1代表失败。

简单使用样例:

创建一个log.txt文件,并且追加输入111222333

  1 #include<stdio.h>
  2 #include<string.h>
  3 #include<stdlib.h>
  4 #include<unistd.h>
  5 #include<sys/types.h>
  6 #include<sys/stat.h>
  7 #include<fcntl.h>
  8 
  9 int main()
 10 {
 11   //只读并且没有文件创建,追加写入
 12   int fd = open("log.txt", O_WRONLY | O_CREAT | O_APPEND, 0666);// rw-rw-rw
 13   if(fd < 0)
 14   {
 15     perror("open:");
 16     return 1;
 17   }
 18 
 19   printf("打开成功, fd %d \n", fd);
 20   const char* s1 = "111111111111";
 21   const char* s2 = "222222222222";
 22   const char* s3 = "3333333333333";
 23   write(fd, s1, strlen(s1));
 24   write(fd, s2, strlen(s1));
 25   write(fd, s3, strlen(s1));
 26 
 27   close(fd);                                                                                                                                                        
 28 
 29   return 0;
 30 }

在这里插入图片描述

文件描述符fd

通过open系统调用函数的理解,发现文件描述符其实就是一个小整数,并且一直是3,为什么呢?
这就要引入stdin,stdout,stderr的概念。

默认文件流stdin/stdout/stderr

在我们操作系统启动的时候,默认会打开三个流,他们就是stdin,stdout,stderr,即标准输入流、标准输出流、标准错误流。对应的硬件分别是:键盘(让我们能输入)、显示器(让我们能看见)、显示器(出错了也能看见)。
在这里插入图片描述

看下面一段程序:

  1 #include<stdio.h>
  4 int main ()
  5 {
  6 
  7   printf("stdin: %d\n",stdin->_fileno);
  8   printf("stdout: %d\n",stdout->_fileno);
  9   printf("stderr: %d\n",stderr->_fileno);
 10   return 0;                                                                                                                                                         
 11 }
 12 

在这里插入图片描述
我们可以猜测,0,1,2是被这默认打开的三个流占用了,所以我们每次再打开文件的时候,被分配的就是从3开始了。


并且在man手册查看一下他们的介绍,发现都是FILE* 类型的。
在这里插入图片描述
因此我们猜测FILE是一个结构体,并且结构体的内部一定有fd。当然这个结构体一定是由C语言提供的。
而我们上面学习了系统调用函数,使用的是fd操纵的文件,我们可以推测C语言的文件操作,一定封装了系统调用的接口,并且通过struct FILE里面的fd来和系统沟通,因为系统只认识fd,不认识FILE*。

下面我将fd与文件的关系可视化出来帮助大家理解:
在这里插入图片描述

解释:通过进程的pcb里面可以找到一个数组,其中fd就是数组的下标,数组内容存着文件的属性信息。因此当我们打开一个文件的时候,OS会在数组中申请一个最小的下标(通常情况下最小为3),然后内容存上结构体的地址,这样我们就能通过fd操作文件啦。

在这里插入图片描述

现在我们知道,文件描述符就是从0开始的小整数。当我们打开文件时,操作系统在内存中要创建相应的数据结构来描述文件。于是就有了file结构体。表示一个已经打开的文件对象。而进程执行open系统调用,所以必须让进程和文件关联起来。每个进程都有一个指针*file,指向一张表files_struct,该表最重要的部分就是包含一个指针数组,每个元素都是一个指向打开文件的指针!所以,本质上,文件描述符fd就是该数组的下标。所以只要拿着文件描述符,就可以找到对应的文件。

文件描述符的分配规则

现在我们已经理清楚,文件描述符是什么,有什么用。那么他的分配规则是什么呢?fd分配最小下标分配原则。
关闭0号文件,那么我们如果打开文件的话描述符就为0,如下:

  1 #include<stdio.h>
  2 #include<string.h>
  3 #include<stdlib.h>
  4 #include<unistd.h>
  5 #include<sys/types.h>
  6 #include<sys/stat.h>
  7 #include<fcntl.h>
  8 
  9 int main()
 10 {
 12   close(0);   //关闭0号文件描述符                                                                                                                                                         
 13   int fd = open("log.txt", O_WRONLY | O_CREAT | O_APPEND, 0666);// rw-rw-rw
 14   if(fd < 0)
 15   {
 16     perror("open:");
 17     return 1;
 18   }
 19 
 20   printf("打开成功, fd %d \n", fd);
 28   close(fd);
 30   return 0;
 31 }

在这里插入图片描述

可以验证OS总是优先分配最小的数组下标,即便是0、1、2号下标也不例外!!!

重定向的概念

输出重定向

看一下下面的代码:

  1 #include<stdio.h>
  2 #include<string.h>
  3 #include<unistd.h>
  4 #include<sys/types.h>
  5 #include<sys/stat.h>
  6 #include<fcntl.h>
  7 
  8 int main ()
  9 {
 10 
 11   close(1);
 12   int fd = open("log.txt", O_WRONLY | O_CREAT | O_TRUNC, 0666);  //fd的文件描述符为1
 13   //下面的内容本应该打印到屏幕上。但实际上却没有打印出来。
 14   printf("打开文件分配的fd为%d\n", fd);  
 15   printf("打印到屏幕上的内容\n");
 16   fprintf(stdout, "hello fprintf\n");
 17   const char* s1 = "hello fwrite\n";
 18   fwrite(s1, 1, strlen(s1), stdout);
 19                                                                                                              
 22   fflush(stdout);
 23   close(fd);
 24   return 0;
 25 }

运行结果:本应该显示在屏幕上的内容却被输出到了文件里!这个现象叫做输出重定向,但是为什么呢?
在这里插入图片描述

下面我将用图例解释一下产生上面情况的原因:
在这里插入图片描述
注意stdin,stdout,stderr在C语言是宏定义,分别被定义成为了0、1、2。在代码中,我们首先关闭了1号文件描述符,然后又打开了文件,显然log.txt文件的文件描述符就是1也就是说1号下标的内容由标准输出(屏幕)变成了指向log.txt的指针。所以,我们在代码中对stdout文件输出内容,在语言层面其实就是对1号文件描述符输出内容,然而语言层面不知道这个改变(因为文件描述符是OS分配的),所以就造成了输出重定向

输入重定向

理解输出重定向例子后,我们很容易就能写出输入重定向。

  8 int main ()
  9 {
 10 
 11   // 关闭stdin
 12   close(0);
 13   int fd = open("log.txt", O_RDONLY);
 14   if(fd<0)
 15   {
 16     perror("open:");
 17     return 1;
 18   }                                                                                                         
 19   printf("fd = %d \n", fd);
 20   char buffer[128];
 21   fgets(buffer, sizeof buffer, stdin);
 22   printf("buffer:%s\n", buffer);
 23   close(fd);
 	}

运行结果:
在这里插入图片描述

可知我们本该需要使用键盘输入的时候,但是却不需要我们输入,而是从我们打开的文件中读取了一行。这就完成了输入重定向工作。

追加重定向

我们实现一直往log.txt追加输出内容的代码:

  1 #include<stdio.h>
  2 #include<string.h>
  3 #include<unistd.h>
  4 #include<sys/types.h>
  5 #include<sys/stat.h>
  6 #include<fcntl.h>
  7 
  8 int main ()
  9 {
 10 
 11   close(1);
      //将文件打开方式变为追加打开即可
 12   int fd = open("log.txt", O_WRONLY | O_CREAT | O_APPEND, 0666);  //fd的文件描述符为1
 13   //下面的内容本应该打印到屏幕上。但实际上却没有打印出来。
 14   printf("打开文件分配的fd为%d\n", fd);  
 15   printf("打印到屏幕上的内容\n");
 16   fprintf(stdout, "hello fprintf\n");
 17   const char* s1 = "hello fwrite\n";
 18   fwrite(s1, 1, strlen(s1), stdout);
 19                                                                                                              
 22   fflush(stdout);
 23   close(fd);
 24   return 0;
 25 }

在这里插入图片描述
运行程序前后,log.txt内容确实被追加了!

dup2()系统调用

上面的例子只是让我们见识一下重定向是什么样子。而实际工程中,我们多使用dup2()系统调用,来完成此功能。

在这里插入图片描述
在这里插入图片描述

把oldfd文件描述符的内容给nwefd(相当于修改的是数组内容)。

看下面代码示例:

  8 int main (int argc, char* argv[])
  9 {
 10   if(argc!=2)
 11   {
 12     return 1;
 13   }
 14 
 15   int fd = open("log.txt", O_CREAT| O_WRONLY|O_TRUNC, 0666);
 16   printf("fd:%d\n", fd);
 17   dup2(fd,1); //将stdout的内容修改为fd
 18   printf("打印屏幕上的内容:%s\n",argv[1]);
 19 
 20   close(fd);
 21   return 0;   
 	}   

运行结果:
在这里插入图片描述
通过上面的例子,我们使用dup2完成了输出重定向!

总结

重定向的本质,其实是在OS内部,更改fd对应的内容指向!!!
重定向很容易解决Linux系统一切皆文件的设计理念。它把显示器、键盘、磁盘当成文件,全部封装成struct file,在用户看来,只需要操作对应的结构体,即可完成重定向的工作。用户根本不需要知道硬件的细节。也恰好能体现封装的思想。

文件缓冲区

  1. 什么是缓冲区?
    缓冲区就是一段内存区域,介于CPU和硬盘之间,因为要执行IO的话,CPU肯定会访问硬盘。CPU的速度是ns级别,硬盘的速度是ms级别。如果让CPU直接访问的话,肯定会拖慢系统的速度。因此我们可以在内存中开辟一小段区域,这段区域就叫做缓冲区。

  2. 缓冲区有什么用?
    缓冲区可以提高效率。
    写透模式(wrrite through):CPU直接向硬盘写入(耽误CPU时间,慢)。
    写回模式:(write back):CPU将数据写到缓冲区后,就干别的事情去了,让缓冲区自己往硬盘写入,写完报告给CPU即可。(不耽误CPU时间,快,,也可以提高用户的相应速度)。

  3. 缓冲区的刷新策略
    立即刷新(写完就立马刷新)、行刷新/行缓冲(遇到\n就立马刷新)、满刷新/全缓冲(写满缓冲区才刷新)。
    一般而言,行缓冲的设备文件:显示器;全缓冲的设备:磁盘文件

深入理解缓冲区的概念

下面我们先看一段代码:

  8 int main ()
  9 {
 10   
 11   //C语言提供的
 12   printf("hello world\n");
 13   const char* s1 = "hello frite\n";
 14   fwrite(s1, 1, strlen(s1), stdout);
 15   fprintf(stdout,"hello fprintf\n");
 16 
 17   //OS系统提供的接口
 18   const char *s2 = "hello write\n";
 19   write(1, s2, strlen(s2));
 20 
 21 
 22   fork();                                                                                                   
 23   return 0;
 24 }

程序运行结果如下:
在这里插入图片描述
**观察发现,程序运行时是正常的,但是当我们重定向到文件里面后,发现C语言提供的函数打印了两次,而系统调用函数只打印一次。**如果我们把fork去掉之后,程序正常运行。我们猜想,这种情况一定和fork有某种关系。

解释:

  1. 如果向显示器打印,刷新策略是行刷新,那么最后执行fork的时候,一定是函数执行完了同时数据已经被刷新了,此时再fork就没有意义了。
  2. 如果对应的程序进行了重定向,要向磁盘文件打印,隐形的刷新策略变成了全缓冲(\n便不管用了),fork的时候,一定是函数已经执行完了,但是数据还没有刷新!因为刷新会清空缓冲区,这涉及到写时拷贝,当父进程结束运行,会刷新缓冲区,同时触发写时拷贝,赋值给子进程,子进程退出时再刷新一份,这样就相当于打印了两次
  3. 为什么系统调用函数只打印一次呢?
    原因是,我们上面提到的缓冲区其实是C语言层面上的,调用C函数时,会将数据写到C提供的缓冲区上。而fork后,出发写时拷贝时,父进程刷新数据到OS缓冲区(1份),子进程刷新到OS缓冲区(2份),因此C语言层面上会打印两次。而write系统调用会直接将数据写到OS缓冲区,因为他是系统提供的函数,不属于C语言函数,因此不涉及C语言层面上的写时拷贝动作,因此只会刷新一次。
    下图解释了这种现象:

在这里插入图片描述

输出缓冲区部分代码解释

在这里插入图片描述

我们在输出缓冲区,当时红色框框的代码没有讲解,现在我们可以解释一下:

  1. 当我们关闭了1号文件,打开了log.txt,此时log.txt的文件描述符为1.
  2. 刷新策略由行刷新,变成了普通刷新,因为是往文件里打印,因此我们输出的数据,其实是在stdout的缓冲区里,并没有刷新呢!
  3. 如果我们提前关闭close(1),因为数据还在缓冲区里,还没有来得及刷新到文件里。所以log.txt文件里什么都没有。
  4. 当我们提前fflush文件的时候,已经把数据刷新到文件里,因此再关闭文件就没事了。

总结

所有的设备按道理来说,都倾向于全缓冲,缓冲区满了,才刷新,这样能进行更少的IO操作,提高效率。因为和外设IO时,数据量的大小不是主要矛盾,和外设预IO的过程(准备过程)是最耗费时间的。
为了照顾到用户体验,显示器一般都是行刷新。极端情况下,我们也可以自定义刷新规则。

**C语言的缓冲区在哪里呢?**和fd一样,存在FILE结构体里面,包含了该文件fd对应的语言层的缓冲区结构。

stdout和stderr的区别

stdout和stderr所对应的硬件都是显示器,但是他们具体有什么区别呢?
名字上:stdout叫标准输出流,stderr叫标准错误流。
让我们看下面一段代码:
该程序输出的1表示使用stdout打印的。输出2表示使用stderr打印的。

  1 #include<iostream>
  2 #include<stdio.h>
  3 
  4 int main()
  5 {
  6   //stdout -> 1
  7   printf("hello printf 1\n");
  8   fprintf(stdout, "hello fprintf1\n");
  9 
 10   //stderr
 11   perror("hello perror 2");
 12 
 13   // cout -> 1
 14   std::cout<< "hello cout 1"<<std::endl;
 15   //cerr -> 2                                                                                                        
 16   std::cerr<<"hello cerr 2"<<std::endl;
 17 
 18   return 0;
 19 }

在这里插入图片描述

程序首先都被打印到了屏幕上,证明他们对应的硬件都是显示器。

我们在此程序的基础上,运行下面的命令:
重定向后,发现stderr的输出仍然打印出来了,但是stdout的输出被重定向到log.txt。
在这里插入图片描述
结论:因为屏幕只有一个,stdin和stdout都打开了显示器文件,即一个显示器文件被打开了两次,有两个文件描述符,输出重定向只是重定向了fd=1描述符,并没有影响到stderr。因此stderr仍然打印到屏幕上。

应用:

//运行下面的命令即可把两种输出,分别重定向到两个文件里。

./myfile > log.txt 2>err.txt

在这里插入图片描述

//运行下面的命令即可把两种输出,重定向到一个文件里。

./myfile > log.txt 2>&1

在这里插入图片描述

总结

一般而言程序如果可能出问题的话,使用stderr或者cerr来打印。
如果是常规文本的打印,建议使用cout或者stdout打印。

自己实现一个perror

在我们的文件操作函数出错之后,出错信息一般都会存在一个全局变量,errno里面,我们一般都使用perror函数来打印错误信息,但是该接口不需要errno。说明该接口一定封装了errno。代码如下:

  5 void myperror(const char* s)
  6 {
  7   //使用errno全局变量打印错误
  8   fprintf(stderr, "%s %s\n",s, strerror(errno));
  9 }

文件系统

文件系统顾名思义是管理文件的系统。如下图是Linux ext2文件系统的磁盘文件系统图。
磁盘是典型的块设备,硬盘分区被划分为一个个的block。一个block的大小是格式化的时候确定的,并且不能更改。其中启动块(Boot Block)的大小是确定的。
在这里插入图片描述

  • Block Group:块组,文件系统会根据分区的大小划分为好多个Block Group。而每个Block Group有着相同的结构。
  • 超级块(Super Block):存放(整个)文件系统本身的结构信息。记录的主要信息有:block和inode的总量,未使用的block和inode的数量,一个block和inode的大小,最近一次挂载的时间,最近一次写入数据的时间,最近一次检查磁盘的时间等其他文件系统的相关信息。Super Block如果被损坏,整个文件系统就被破坏了。因此,有好多个Block Group都有Super Block。
  • GDT(Group Descriptor Table):块组描述符,描述块组的属性信息,这个块组多大,已经使用了多少,有多少inode,已经占用了多少,还剩多少,一共有多少个block,使用了多少。
  • 块位图(Block Bitmap):位图中记录着哪个数据块已经被占用,哪个数据块没有被占用。
  • inode位图(inode Bitmap):每个bit表示一个inode是否空闲可用。
  • inode Table:i结点表,存放文件属性和文件大小,所有者,最近修改时间等。
  • Data blocks:数据区存放文件内容。

众所周知:文件 = 属性 + 数据因此flie = inode Table + Data blocks

inode

inode是一个结构体,存放着文件的各种属性。

struct inode
{
	//文件大小
	//文件的inode编号
	//其他属性
	int blocks[15] //(0-11是直接索引,12-15是间接索引)
}
  • inode与文件名的关系:我们使用文件名去寻找文件,但是linux其实并不认识文件名,它只认识inode号,因此,在每个目录下面<文件名,inode>都有着对映的键值对,可以帮助转化成inode。
  • 目录也是文件,也有ionde号,也有data Block。
    因此对于一个目录,进入目录需要X(执行)权限,创建文件需要W(写)权限(要写数据块),显示文件名与属性r(读)权限(要读数据块)。

创建文件过程:首先os申请一个inode号,并且为之分配一个数据块,然后更新inode表。完成之后,更新目录的data block。

发现系统还有空间,为什么不能创建文件?

因为inode和data block是固定的。可能是没有ionde号了。

软硬链接

  • 硬链接是通过inode引用另外一个文件,引用计数+1,inode号相同,相当于共享一个inode。
  • 软链接是通过名字引用另外一个文件,引用计数不变,新inode号,相当于一个新的inode号指向老的inode号,相当于快捷方式。

在这里插入图片描述

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

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

相关文章

基于ssm的儿童影楼拍摄管理系统的设计与实现+vue论文

基于SSM的儿童影楼拍摄管理系统的设计与实现 摘 要 当下&#xff0c;正处于信息化的时代&#xff0c;许多行业顺应时代的变化&#xff0c;结合使用计算机技术向数字化、信息化建设迈进。以前相关行业对于商品信息的管理和控制&#xff0c;采用人工登记的方式保存相关数据&…

实时云渲染是什么?它的应用方向有哪些?

实时云渲染有三个关键词&#xff0c;"实时"、"云"和"渲染"&#xff0c;它们分别表示&#xff1a;同步、云服务器计算和图像生成过程&#xff0c;简单来说就是使用第三方平台快速完成渲染任务&#xff0c;它有两个实用方向&#xff1a; 一、实时渲…

4.4 媒资管理模块 - 分布式任务处理介绍、视频处理技术方案

媒资管理模块 - 视频处理 文章目录 媒资管理模块 - 视频处理一、视频转码1.1 视频转码介绍1.2 FFmpeg 基本使用1.2.1 下载安装配置1.2.2 转码测试 1.3 工具类1.3.1 VideoUtil1.3.2 Mp4VideoUtil1.3.3 测试工具类 二、分布式任务处理2.1 分布式任务调度2.2 XXL-JOB 配置执行器 中…

Master01节点免密钥登录其他节点

1、执行命令 ssh-keygen -t rsa&#xff0c;一直敲回车 2、for i in k8s-master01 k8s-node01 k8s-node02;do ssh-copy-id -i .ssh/id_rsa.pub $i;done 输入yes和对应节点密码

PostGIS教程学习十九:基于索引的聚簇

PostGIS教程学习十九&#xff1a;基于索引的聚簇 数据库只能以从磁盘获取信息的速度检索信息。小型数据库将完全位于于RAM缓存&#xff08;内存&#xff09;&#xff0c;并摆脱物理磁盘访问速度慢的限制。但是对于大型数据库&#xff0c;对物理磁盘的访问将限制数据库的信息检…

在VS Code中安装Copilot与安装其他扩展的方法一样,只需简单几步

GitHub Copilot是由OpenAI和GitHub开发的人工智能工具。它的目的是通过自动完成代码来帮助开发人员使用集成开发环境&#xff08;IDE&#xff09;&#xff0c;如Visual Studio Code。它目前仅作为技术预览版提供&#xff0c;因此只有在候补名单上被认可的用户才能访问它。对于用…

纯血鸿蒙「扩圈」100天,酝酿已久的突围

坦白讲&#xff0c;去年参加华为开发者大会看到HarmonyOS NEXT&#xff08;仅运行鸿蒙原生应用&#xff0c;所以也称作「纯血鸿蒙」&#xff09;的时候&#xff0c;小雷也没料想到鸿蒙原生应用生态的发展速度会如此之快。 9月25日&#xff0c;华为正式对外宣布启动HarmonyOS NE…

PTA✨C语言 就不告诉你

7-7 就不告诉你 分数 15 全屏浏览题目 切换布局 作者 CHEN, Yue 单位 浙江大学 做作业的时候&#xff0c;邻座的小盆友问你&#xff1a;“五乘以七等于多少&#xff1f;”你应该不失礼貌地围笑着告诉他&#xff1a;“五十三。”本题就要求你&#xff0c;对任何一对给定的正…

2024年美国大学生数学建模思路 - 复盘:人力资源安排的最优化模型

文章目录 0 赛题思路1 描述2 问题概括3 建模过程3.1 边界说明3.2 符号约定3.3 分析3.4 模型建立3.5 模型求解 4 模型评价与推广5 实现代码 建模资料 0 赛题思路 &#xff08;赛题出来以后第一时间在CSDN分享&#xff09; https://blog.csdn.net/dc_sinor?typeblog 1 描述 …

[前车之鉴] SpringBoot原生使用Hikari数据连接池升级到动态多数据源的深坑解决方案 RocketMQ吞掉异常问题排查

文章目录 背景说明蒙蔽双眼口说无凭修补引发的新问题解决配置问题 本地监控佐证万法归元 背景说明 当前业务场景我们使用原生SpringBoot整合Hikari数据源连接池提供服务&#xff0c;但是近期业务迭代需要使用动态多数据源&#xff0c;很自然想到dynamic-source&#xff0c;结果…

Python教程37:使用turtle画一个戴帽子的皮卡丘

---------------turtle源码集合--------------- Python教程36&#xff1a;海龟画图turtle写春联 Python源码35&#xff1a;海龟画图turtle画中国结 Python源码31&#xff1a;海龟画图turtle画七道彩虹 Python源码30&#xff1a;海龟画图turtle画紫色的小熊 Python源码29&a…

linux 系统安全及应用

一、账号安全基本措施 1.系统账号清理 1.将用户设置为无法登录 /sbin/nologin shell——/sbin/nologin却比较特殊&#xff0c;所谓“无法登陆”指的仅是这个用户无法使用bash或其他shell来登陆系统而已&#xff0c;并不是说这个账号就无法使用系统资源。举例来说&#xff0c;…

JAVA基础学习笔记-day15-File类与IO流

JAVA基础学习笔记-day15-File类与IO流 1. java.io.File类的使用1.1 概述1.2 构造器1.3 常用方法1、获取文件和目录基本信息2、列出目录的下一级3、File类的重命名功能4、判断功能的方法5、创建、删除功能 2. IO流原理及流的分类2.1 Java IO原理2.2 流的分类2.3 流的API 3. 节点…

SNP浅谈SAP系统增强及二次开发

SAP 系统增强和二次开发是指在 SAP 系统的基础上&#xff0c;对现有功能进行扩展和增强&#xff0c;以满足特定业务需求。增强和二次开发可以通过不同的方法实现&#xff0c;包括&#xff1a; ■ 数据集成&#xff1a;通过创建数据接口&#xff0c;实现 SAP 系统与其他系统之间…

视频智能分析/边缘计算AI智能分析网关V4区域入侵检测算法如何配置?

边缘计算AI智能分析网关&#xff08;V4版&#xff09;部署了近40种AI算法模型&#xff0c;支持对接入的视频图像进行人、车、物、行为等实时检测分析&#xff0c;并上报识别结果&#xff0c;并能进行语音告警播放。算法配置后&#xff0c;即可对监控视频流进行实时检测&#xf…

基于 Canvas 的多行文本溢出方案

说到文本溢出&#xff0c;大家应该都不陌生&#xff0c;中文网络上的文章翻来覆去就是下面3种方法&#xff1a; 单行文本溢出 这是日常开发中用的最多的&#xff0c;核心代码如下&#xff1a; p {width: 300px;overflow: hidden; white-space: nowrap; /*文本不会换行*/text…

基于模块自定义扩展字段的后端逻辑实现(二)

目录 一&#xff1a;创建表 二&#xff1a;代码逻辑 上一节我们详细讲解了自定义扩展字段的逻辑实现和表的设计&#xff0c;这一节我们以一个具体例子演示下&#xff0c;如何实现一个订单模块的自定义扩展数据。 一&#xff1a;创建表 订单主表: CREATE TABLE t_order ( …

rime中州韵小狼毫 中英互绎 滤镜

英文在日常生活中已经随处可见&#xff0c;我们一般中英互译需要使用专业的翻译软件来实现。但如果我们在输入法中&#xff0c;在输入中文的时候&#xff0c;可以顺便瞟一眼对应的英文词汇&#xff0c;或者在输入英文的时候可以顺便了解对应的中文词汇&#xff0c;那将为我们的…

1.8 day6 IO进程线程

使用有名管道实现两个进程之间的通信 进程A #include <myhead.h> int main(int argc, const char *argv[]) {//创建两个文件描述符用于打开两个管道int fd1-1;int fd2-1;//创建一个子进程int pid-1;if((fd1open("./mkfifo1",O_RDWR))-1){perror("open er…

OpenAI ChatGPT-4开发笔记2024-03:Chat之Tool和Tool_Call(含前function call)

Updates on Function Calling were a major highlight at OpenAI DevDay. In another world,原来的function call都不再正常工作了&#xff0c;必须全部重写。 function和function call全部由tool和tool_choice取代。2023年11月之前关于function call的代码都准备翘翘。 干嘛…