Linux:文件操作

news2024/10/7 4:27:43

目录

一、关于文件

1、文件类的系统接口

2、文件的含义

二、文件操作

1、C语言文件相关接口

2、系统接口

open

close

write

read

三、文件描述符

关于fd

fd的分配规则

输出重定向示例

输入重定向示例

追加重定向示例

dup2函数

缓冲区

stdout与stderr

perror


一、关于文件

1、文件类的系统接口

首先不同语言都有不同的文件操作接口,C语言、C++、java都有各自的文件接口,而这些文件接口的底层,其实是封装的系统接口

之所以各个语言不直接使用文件类的系统接口,是因为系统接口相比较各个语言封装出来的接口,难度较大,学习成本比较高,各种语言对系统接口做封装,是为了让接口更好的使用

其次,也是为了跨平台这个特性,如果每种语言对系统接口不封装,直接调用系统接口,那么所有的文件操作都必须使用操作系统接口,无法在其他平台运行,是不具备跨平台特性的

2、文件的含义

说起文件,大部分人都想的是普通的磁盘文件,例如记事本打开的文本文件、.exe之类的文件

其实站在系统的角度,能够被input读取,output写出的设备都叫做文件,例如:键盘、显示器、磁盘、网卡、显卡等外设,都可以被称为文件

二、文件操作

1、C语言文件相关接口

我们先在Linux中写C语言中学习的文件接口:

以w的方式打开,如果文件不存在,会创建一个新文件,那么这个文件会创建在哪呢

很显然会创建在当前路径下,而当前路径指:一个进程运行起来的时候,每个进程都会记录自己当前所处的工作路径,而这个工作路径就是当前路径

上面的代码中,test.txt这个文件是不存在的,该路径下只有两个文件:

所以在编译运行file.c后,test.txt会在该路径下创建出来:

由于当前进程的工作路径在这里,所以创建出来的test.txt也就在这个路径下了


以w方式打开文件时,不论文件里面是否有内容,打开文件时做的第一件事就是清空文件内容,哪怕我们什么都不干,只是打开关闭文件,文件内容都会被清空,下面举个例子:

我们向文件test.txt中写入"hello"

查看test.txt内容:

这时改变file.c的内容,将fprintf的相关代码删除:

然后再编译运行myfile:

发现test.txt里面的内容没有了,大小为0


有了上面打开文件就会清空文件内容的基础,再看下面的例子:

先cat test.txt,发现文件里没有内容

接着echo输出重定向的方式向test.txt写了一个字符串hello,cat test.txt发现确实写入了

然后执行>test.txt后,再cat,发现又被清空了

这里的>符号,可以当做一个命令,表示要往文件里写入的,而向文件写入首先做的就是打开这个文件,上面也提到了,打开文件做的第一件事就是清空文件内容,所以我们就可以明白为什么执行完>test.txt后,test.txt中内容就被清空了

以上就是复习的C语言相关文件接口


2、系统接口

上面提到的C语言的库函数,底层一定会调用系统调用接口

系统调用接口有open、close、write、read

open

通过man了解一下open:

有三个头文件需要包含,然后看下面的两个open后面的参数

参数pathname:代表需要打开文件的路径 + 文件名

参数flags:表示选项(O_RDONLY、O_WRONLY、O_RDWR必须包含这三个其中一个)

参数mode:表示权限(如果传入0666,就表示拥有者、所属组、other的权限都是rw-)

选项有很多,例如:O_RDONLY(只读)、O_WRONLY(只写)、O_RDWR(读写)、O_CREAT(文件不存在就创建)、O_TRUNC(打开文件时如果有原本内容就清空原始内容)

像上面的这些是O_RDONLY、O_WRONLY、O_RDWR,其实就是宏定义,而open后面的参数只有一个flags,如何传递这么多的标记位,这里就和C++中的位图类似了,用比特位传递

关于open的返回值:

如果成功了,会返回一个文件描述符        

如果失败了,就会返回-1

关于两个open的使用场景:

三个参数的open是用于文件不存在,第三个参数可以控制该文件的权限

两个参数的open是用于文件已经存在的场景


下面示范一下如何用比特位传递多个标记位:

定义了三个宏A、B、C,分别是0x1(0000 0001)、0x2(0000 0010)、0x4(0000 0100)

main函数中给test传递的参数A | B,就是0000 0001 | 0000 0010即传递上去的值为0000 0011

这时传递上去的0000 0011与A(0000 0001),B(0000 0010)按位与都满足,所以会打印里面的语句

运行结果为:

满足传上去的参数要求

这里的例子就说明了,如果想传入多个标志位,则用 | (按位或)的方式就能做到,下面会用到这个结论


下面使用一下open:

首先第一个umask是一个函数,用于在当前进程重置umask值,以便于我们open中传递的第三个关于权限的参数受到系统中umask值的影响

open中的第二个参数,O_WRONLY | O_CREAT,O_WRONLY是以w的方式打开,O_CREAT是创建一个文件,如果文件不存在必须要加上O_CREAT选项,中间的|在上面的例子中说到过,传递多个标志位时用|连接

运行结果如下:

成功运行


close

通过man查看close

这里的close使用就很简单了,包含一个头文件unistd.h

关闭文件时,将刚刚返回的文件标识符传入即可

代码中添加close即可:


write

通过man查看write

包含一个头文件unistd.h

参数的含义就是:向一个fd里,写特定的buf,字符个数是count个

下面演示用法:

我们给了一个const char*类型的字符串,使用write接口

运行结果如下:

成功向文件中写入了I am write

但是这里会有一个问题,我们在C语言中,写入文件时,如果文件中有内容,再重写其他内容时会被覆盖,而在Linux中则会存在问题,如下:

将字符串str改为"111",然后在运行,查看现在test.txt中的内容:

可以看到,并不是我们所想的111,而是111覆盖了刚刚内容的前三个字符的位置,反而test.txt中的内容变为了111m write

想解决这个问题,只需要加上选项O_TRUNC,即创建文件时如果有原始内容,则清空原始内容

如下所示:

此时再重新运行,打印test.txt中内容就变为我们想要的样子了:

这里也应证了我们最开始所说的文件类的系统接口学习成本比较高,难度比较大,所以各种语言会封装文件接口,使用起来更简单些

我们使用的   open("test.txt",O_WRONLY|O_CREAT|O_TRUNC,0666)

与C语言中的fopen("test.txt","w")的功能是一样的,更看出其中的难易

上面用的是w的功能,如果是a(追加),只需将O_TRUNC换为O_APPEND即可:

这时多运行几次,结果为:

这时代码的open("test.txt",O_WRONLY|O_CREAT|O_APPEND,0666)

与C语言的fopen("test.txt","a")功能相同


read

通过man查看read

同样包含一个头文件unistd.h

参数的含义就是:从特定的文件描述符fd读取数据,读到buf里面,读取的个数是count个

我们先向text.txt中写入数据:

接着使用read:

首先将open后面的参数变为O_RDONLY,只读,然后创建一个buf的字符数组,memset将buf中的数据全部置为'\0',read读文件,最后打印出读取的内容:

最终读取成功


三、文件描述符

关于文件描述符fd,上面的代码中有打印过,接下来将代码做以改造,多打开几个文件,再观察文件描述符:

创建4个test.txt文件,观察每次返回的文件描述符fd:

可以看到test.txt1~4的文件描述符分别是3、4、5、6,那么为什么是从3开始的,0、1、2是对应的什么,其实在C语言中我们就学过了,0、1、2分别对应的是stdin(标准输入)、stdout(标准输出)、strerr(标准错误),是被默认打开的

stdin、stdout、strerr他们的类型都是FILE*的


下面举例验证一下0、1、2这三个文件描述符:

我们C语言中使用的fprintf,如果要往显示器上写,第一个参数就是stdout

而系统接口write,第一个参数是fd,我们可以传入1,观察是不是往显示器上写入:

结果为:

可以发现,传入文件描述符1,也是往显示器上写入的,与stdout功能相同


下面示例文件描述符为0的stdin

系统接口read的第一个参数传入0,表示stdin

read的返回值是读入的个数,如果大于0,就说明读入成功了

结果为:

可以看到,也可以通过传入文件描述符0,实现stdin的功能


关于fd

fd的本质是指针数组的下标

在内核中,每一个进程都是可以打开多个文件的,也就是一对多的关系

而为了管理这些文件,操作系统需要构建一个file结构体,包含了被打开文件的几乎全部内容,如果被打开的文件很多,就用双链表组织起来

而我们刚刚说到的0、1、2,就是一个指针数组的下标,表示这个指针数组前三个位置存储的就是stdin、stdout、stderr的位置,Linux进程默认会打开这三个文件描述符,0、1、2对应的物理设备一般是:键盘、显示器、显示器

这里的指针数组中的每一个元素都是一个指向打开文件的指针

而我们上面所举例子中新创建了4个test.txt文件,他们返回的fd分别是3、4、5、6,也就代表着他们所在的位置就是这个指针数组的3、4、5、6下标,在数组中做哈希索引,索引之后就能找到被打开的文件对象

进程打开一个文件,操作系统会创建一个struct file对象,然后在该进程的指针数组中,分配一个没有被使用的数组空间,接着把新的文件地址填在这里面,然后返回对应的文件描述符下标给用户使用,所以fd在内核中,本质是一个指针数组的下标


fd的分配规则

fd的分配规则是:优先最小的,没有被占用的文件描述符

正常情况下,我们创建一个新文件,文件描述符是3,因为0、1、2是默认被打开的

结果为:

如果我们提前把文件描述符0关了(close),那么新创建一个文件会被分配到哪个文件描述符:

这时结果为:

所以可以明白,文件描述符基本的分配规则就是:从头遍历,找最小的且没有被占用的文件描述符


输出重定向示例

那么如果close的是1呢,如图:

创建test.txt前,close(1),观察现象:

我们运行myfile,没有任何内容,但是cat查看test.txt时却发现,本该打印在显示器上的内容出现在了test.txt中

这是因为,在我们创建test.txt前,关闭了文件描述符1,也就是系统默认打开的stdout,它所对应的指针数组下标为1的位置为空了,这时创建test.txt,按照fd的分配原则,将文件描述符1就分配给了test.txt

我们所使用的printf、fprintf中,都是包含stdout的,所以执行时默认就是执行了stdout,而stdout本身默认的文件描述符就是1,刚刚分配文件描述符是底层做的,上层并不清楚,所以它们就照常往1里面写,但是写完后,通过进程找到指针数组,再通过指针数组的下标1找到所对应的文件,而这时1所对应的文件早已不是stdout,而是test.txt,因此我们printf的内容都在test.txt中可以看到

本来应该显示到显示器的内容,被写入到了文件中,这就是输出重定向

以上所说的就叫做重定向的原理!

重定向的本质:其实是在操作系统内部,更改fd对应的内容的指向


输入重定向示例

先正常使用fgets函数,观察正常打印的结果:

创建了一个test.txt文件,理应分配的文件描述符是3

并且下面的fgets第三个参数是stdin,是从键盘读取的

所以先打印fd:3,然后在键盘输入hello,显示器就打印了一个hello

上面是正常情况,下面演示输入重定向的情况,即close(0)时的情况:

首先我们将test.txt的内容更改为hello test

然后在open文件test.txt前,close(0):

这时根据fd的分配规则,显然test.txt的文件描述符就分配为了0

运行结果为:

可以看到,打印出fd:0,但是接下来本应该从键盘读取,却变为了直接读取文件test.txt的内容

原因也很简单,我们close(0)后,原本数组下标为0的的位置是指向stdin的,现在变为了指向文件test.txt,而上层并不知道底层做了这些改变,在执行fgets时依然是从文件描述符0中读取,而这时文件描述符已经变为了test.txt,所以执行时,根据文件描述符0指向的地址是test.txt的位置,并不是stdin的,所以不需要等待从键盘输入再打印,而是直接打印test.txt的内容

而上面所说的,本来应该从键盘中读取的内容,变为了从文件中读取,这就是输入重定向的定义!


追加重定向示例

这是上面所举例的输出重定向

追加重定向只需将open中的参数O_TRUNC(清空)改为O_APPEND(追加)即可

这时看结果:

第一次执行,打印了原有的内容hello test,且追加了fd:1

又对执行了两次,可以看到test.txt的内容也多了两行内容

这就是追加重定向


dup2函数

而我们如果想实现重定向,上面的方法可以是可以,但是比较麻烦,下面说说更好的方法去实现重定向

首先学习函数dup2

dup2中有两个参数oldfd和newfd

关于这两个参数需要详细说明:

oldfd是要拷贝到newfd中去,所以最终会留下oldfd

所以如果我们创建一个文件,这个文件的文件描述符就是3,这时要进行输出重定向,即将文件描述符1(stdout[显示器])改变指向,所以需要将3拷贝到1中去,最后留下的就是3,即所创建的文件了

所以实现输出重定向使用dup2时,oldfd是3,newfd是1,具体示例如下:

使用fprintf时顺便复习一下命令行参数,这时结果为:

如果我们直接执行myfile这个可执行文件,就进入第一行语句if (argc != 2)中了,因为此时只有myfile,argc == 1

接下来我们在myfile后面跟上了一个字符串,这时就符合要求,也打印出来了我们输入的字符串

以上是不使用dup2的情况,下面使用dup2进行输出重定向:

上面说到的,第一个参数是oldfd,第二个参数是newfd,要保留oldfd,所以我们传入fd,即test.txt的fd

观察结果:

dup2函数实现了输出重定向


dup2函数追加重定向:

只需将open的第二个参数中的O_TRUNC变为O_APPEND即可:

结果为:

也能很轻松地实现


缓冲区

缓冲区就是一段内存空间

有缓冲区能够提高整机的效率,也能够提高用户的响应速度

缓冲区的刷新策略:

1、立即刷新

2、行刷新(行缓冲,例如遇到\n)

3、满刷新(全缓冲)

也存在特殊情况:

1、用户强制刷新(例如fflush)

2、进程退出

一般采用行缓冲策略的设备文件是显示器,采用全缓冲策略的是磁盘

而所有的设备都是倾向于全缓冲的,因为缓冲区满了才刷新,IO操作少,访问外设的次数变少,从而提高效率

设备是倾向于全缓冲,但是其他的刷新策略,都是根据具体情况所做出的改变:

例如显示器是行缓冲刷新,是因为显示器是直接给用户看的,需要照顾用户体验


下面看一个例子:

先执行printf、fprintf、fputs,然后执行write,最后调用fork()

在调用fork()时,上面的函数已经执行完毕了

下面观察结果:

编译后直接运行myfile,发现在显示器上打印的是4行

但是向普通文件打印时,却变成了7行

通过观察可以发现,C语言的接口是打印了两次的,而系统接口只打印了一次

通过这个结果,我们可以看出来,执行fork()后,并不影响系统接口,所以如果存在缓冲区,是由C标准库提供的,而不是操作系统提供,因为如果是操作系统提供的,那么上面的结果应该是一样的,write也应该打印两次

所以如果我们使用fprintf、fputs等接口,应该是先写入C标准库的缓冲区中,然后我们就不需要关心了,何时刷新都是由C标准库管理的

而如果使用的是write接口,就会直接将数据写给操作系统,不需要经过缓冲区


下面说明上面代码在显示器上打印,和重定向到文件中,为什么结果不一样的原因:

第一,如果向显示器打印,这时的刷新策略是行刷新,每遇到一个\n就刷新一次,那么最后执行fork的时候,一定是函数执行完了并且数据已经被刷新了,此时的fork无意义!所以在显示器上打印时,只有4个结果

第二, 如果你进行了重定向,就变为了要向磁盘文件打印,这时的刷新策略变成了全缓冲!所以printf、fprintf、fputs字符串后面的\n便没有意义了,此时执行fork函数,有父进程和子进程,而父进程的数据还在缓冲区当中,fork函数后面就执行return 0即进程退出

上面说到特殊情况,进程退出时会刷新缓冲区,而刷新的过程其实就是写入的过程可以理解为一个进程退出时为了不影响另一个进程使用现有的数据,所以会发生写时拷贝,所以我们明白了,上面凡是在C标准库的缓冲区的数据,都出现了两份,而直接直接写给操作系统的系统接口,只有一份

上面了解到,之所以打印到显示器上内容和打印到文件里的内容不一样,是因为打印到文件里时,改变了刷新策略,变为了全缓冲,导致父进程的数据没有被刷新出来,还保存在缓冲区中,所以执行fork后,发生写时拷贝,打印出来了2份数据

那如果我们在fork前,执行fflush函数,强制刷新缓冲区,这时执行fork时,缓冲区中没有数据,是不是就像我们所推测的那样,上面两种方式打印的内容就相同了,如下图:

观察结果:

通过观察可以发现,执行完fflush后,两种方式的打印的内容就完全相同了


stdout与stderr

stdout与stderr对应的文件描述符分别是1和2

而1和2对应的都是显示器文件,但是它们是不一样的

在输出或追加重定向时会有区别:

我们分别在打印时加上->区别是1还是2

下面看结果,正确运行时,都能打印到显示器上:

如果输出重定向:

我们会发现,往2号文件描述符写的内容依旧打印到显示器上了,而只有往1号文件描述符写的内容才重定向到文件中

所以我们明白了,这里的重定向其实是往1号文件描述符写的

1和2对应的都是显示器文件,可以理解为打开了两份,重定向时把正确的信息写到文件里,错误信息依旧打印到显示器上

因此一般情况下,如果程序可能存在问题,建议使用stderr或cerr来打印

如果是常规的文本文件,建议使用stdout或cout打印


针对标准输出和标准错误,如果我们想将这两种分开打印,可以进行如下操作:

这时就可以将调用stdout的打印到right.txt中,调用strerr的打印到err.txt中了

我们可以将标准输出和标准错误分开,2>err.txt就是将本来应该显示到2号文件描述符的内容显示到err.txt上

那如果我们就是想将stdout和stderr的内容都放在一个文件中,就可以进行如下操作:

这时就能实现上述要求


perror

上面代码中出现了perror这个函数,其实我们可以发现使用perror后,打印结果多了一个success,其实这个函数会自动根据全局的错误码,输出对应的错误原因

例如我们使用open时,经常在下面的if语句里,使用perror("open"),就是表示,如果open失败了,可以打印失败的错误信息

假设我们使用open,去读test文件,if语句中使用perror

打印结果如下:

通过ls可以发现,当前路径下并没有test文件,所以open的返回值小于0,即进入if语句执行perror

通过结果可以看到,perror会自动调用错误码输出错误信息,例如上述例子的错误信息就是不存在该文件


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

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

相关文章

大促期间如何应对低价链接

一年一度的大促双十一即将来临,品牌商、经销商在忙着出货,消费者也在积极比价,大促最直观的感觉就是价格,没有低价的大促是没有意义的,所以品牌要管的不是低价产品,而是在不受规则下的低价行为。 力维网络有…

KnowledgeGPT:利用检索和存储访问知识库上增强大型语言模型10.30

利用检索和存储访问知识库上增强大型语言模型 摘要引言2 相关研究3方法3.1 任务定义3.2 知识检索3.2.1 代码实现3.2.2 实体链接3.2.3 获取实体信息3.2.4 查找实体或值3.2.5 查找关系 3.3 知识存储 4 实验 摘要 大型语言模型(LLM)在自然语言处理领域展现…

SpringBoot 集成 Camunda

SpringBoot 集成 Camunda 1 pom.xml2 application.yml3 SQL4 启动5 进入流程页面 1 pom.xml <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XML…

nodejskoaMySQL 蒲公英旅游系统15565-计算机毕业设计项目选题推荐(附源码)

摘 要 随着社会的发展&#xff0c;社会的各行各业都在利用信息化时代的优势。计算机的优势和普及使得各种信息系统的开发成为必需。蒲公英旅游系统设计&#xff0c;主要的模块包括查看后台首页、轮播图&#xff08;轮播图管理&#xff09;、公告管理&#xff08;公告&#xff…

循环神经网络(RNN)与长短期记忆网络(LSTM)

前言&#xff1a; 通过前面的学习&#xff0c;我们以BP神经网络为基础&#xff0c;认识到了损失函数&#xff0c;激活函数&#xff0c;以及梯度下降法的原理&#xff1b;而后学习了卷积神经网络&#xff0c;知道图像识别是如何实现的。今天这篇文章&#xff0c;讲述的就是计算机…

X3DAudio1_7.dll是什么,解决计算机找不到X3DAudio1_7.dll文件的方法

作为一位程序员&#xff0c;我深知x3daudio1_7.dll丢失对电脑用户的影响。这个文件是DirectX的一个组件&#xff0c;它负责处理音频输出和输入。当这个文件丢失时&#xff0c;可能会导致电脑无法正常播放音频&#xff0c;甚至出现蓝屏等问题。那么&#xff0c;面对这个问题&…

xhadmin多应用SaaS框架的怎么进入后台?

xhadmin是什么&#xff1f; xhadmin 是一套基于最新技术的研发的多应用 Saas 框架&#xff0c;支持在线升级和安装模块及模板&#xff0c;拥有良好的开发框架、成熟稳定的技术解决方案、提供丰富的扩展功能。为开发者赋能&#xff0c;助力企业发展、国家富强&#xff0c;致力于…

Jetpack:025-Jetpack中的多点触控事件

文章目录 1. 概念介绍2. 使用方法2.1 缩放事件2.2 旋转事件2.3 平移事件2.4 综合事件 3. 示例代码4. 内容总结 我们在上一章回中介绍了Jetpack中滚动事件相关的内容&#xff0c;本章回中主要介绍 多点解控事件。闲话休提&#xff0c;让我们一起Talk Android Jetpack吧&#xf…

国际阿里云CDN加速OSS资源教程!

当您需要加速OSS上的静态资源时&#xff0c;可以通过阿里云CDN加速OSS域名&#xff0c;实现静态资源的访问加速。本文详细介绍了通过CDN控制台实现OSS加速的操作流程和应用场景。 客户价值 阿里云OSS可提供低成本的存储&#xff0c;CDN可以实现静态资源加速分发。使用OSS作为C…

浮点数和定点数(上):怎么用有限的Bit表示尽可能多的信息?

目录 背景 浮点数的不精确性 定点数的表示 浮点数的表示 小结 背景 在我们日常的程序开发中&#xff0c;不只会用到整数。更多情况下&#xff0c;我们用到的都是实数。比如&#xff0c;我们开发一个电商 App&#xff0c;商品的价格常常会是 9 块 9&#xff1b;再比如&…

LLM - 训练与推理过程中的 GPU 算力评估

目录 一.引言 二.FLOPs 和 TFLOPs ◆ FLOPs [Floating point Opearation Per Second] ◆ TFLOPs [Tera Floating point Opearation Per Second] 三.训练阶段的 GPU 消耗 ◆ 影响训练的因素 ◆ GPT-3 训练统计 ◆ 自定义训练 GPU 评估 四.推理阶段的 GPU 消耗 ◆ 影响…

Azure机器学习 - 在 Azure 机器学习中上传、访问和浏览数据

目录 一、环境准备二、设置内核三、下载使用的数据四、创建工作区的句柄五、将数据上传到云存储空间六、访问笔记本中的数据七、创建新版本的数据资产八、清理资源 机器学习项目的开始阶段通常涉及到探索性数据分析 (EDA)、数据预处理&#xff08;清理、特征工程&#xff09;以…

WebService接口方式是什么

业务应用系统指标采集采用WebService接口方式&#xff0c;这表明系统通过WebService这种网络服务的形式来收集和交换业务应用的运行指标和数据。 WebService是一种在网络上提供服务的方式&#xff0c;它允许不同的应用程序在网络上进行交互和通信&#xff0c;无论它们是用什么…

javaEE -14(10000字 JavaScript入门 - 1)

一&#xff1a;初始 JavaScript JavaScript (简称 JS)是世界上最流行的编程语言之一&#xff0c;它是一个脚本语言, 通过解释器运&#xff0c;主要在客户端(浏览器)上运行, 现在也可以基于 node.js 在服务器端运行. JavaScript 和 HTML 和 CSS 之间的关系&#xff1a; HTML…

Spring IOC - ConfigurationClassPostProcessor源码解析

上文提到Spring在Bean扫描过程中&#xff0c;会手动将5个Processor类注册到beanDefinitionMap中&#xff0c;其中ConfigurationClassPostProcessor就是本文将要讲解的内容&#xff0c;该类会在refresh()方法中通过调用invokeBeanFactoryPosstProcessors(beanFactory)被调用。 5…

dsm 和 大五人格

问题记录 1. 九型人格好像有很多层, 各层会有对应? 笔迹分析. 2. 还要结合行为吧? 书: dsm5 失序的人格 动力取向精神 问题: 大五人格和dsm的渊源, 觉得dsm太粗略了,搞个大五海洋. 问题: 很内向, 然后喜欢摄影, 也喜欢看b站上其他专业博主上传的摄影vlog. 跟他交流的时候又…

图的广度优先遍历讲解附Java代码加详细注释

目录 引入 代码实现 复杂度分析 引入 类比树的广度优先遍历&#xff08;层序遍历&#xff09;&#xff0c;通过一个队列不断地实现出队的同时把左右孩子入队的操作实现广度优先遍历&#xff0c;值得注意的是图是否有环的情况。 用相似的方法可以实现图的广度优先遍历&#…

Linux:Docker的介绍(1)

Docker官网 Docker: Accelerated Container Application Developmenthttps://www.docker.com/ docker是什么&#xff1f; 是一种轻量级的‘虚拟机’ 在Linux容器里运行应用的开源工具 Docker 是一个开源的应用容器引擎&#xff0c;让开发者可以打包他们的应用以及依赖包到一个…

跟着步骤,快速实现图书行业小程序商城

跟着步骤&#xff0c;快速实现图书行业小程序商城 打造独特图书购物体验&#xff0c;小程序商城制作指南 轻松搭建图书馆与书店的线上商城小程序 值得一试的图书教材小程序商城搭建方法 图书商城小程序制作指南&#xff0c;助你成为行业领袖 实战教程&#xff1a;如何制作…

LabVIEW对多个同一类型控件进行操作

LabVIEW对多个同一类型控件进行操作 有时候LabVIEW要多多个同一类的控件进行操作&#xff0c;如对tab中某个page中所有String控件设为dissable。就可以用如下的方式。className是获取不同类型的控件。通过类型选择&#xff0c;可以选择所有的String控件&#xff0c;并可对特定…