【Linux学习笔记】基础IO

news2024/10/6 18:22:47

这里写目录标题

  • 1. 系统文件I/O
    • 1.1. 接口介绍
    • 1.2. 库函数接口与系统接口的关系
  • 2. 文件描述符fd
    • 2.1. 0&1&2文件描述符
    • 2.2. 文件描述符的分配规则
    • 2.3. 重定向
    • 2.4. 重定向系统调用
    • 2.5. 进程独立性
  • 3. Linux下一切皆文件
  • 4. 缓冲区
    • 4.1. 缓冲区的理解
    • 4.2. 缓冲区的位置
  • 5. 理解文件系统
    • 5.1. 认识磁盘
    • 5.2. 文件管理
    • 5.3. 分组的管理
  • 6. 软硬连接
    • 6.1. 软链接
    • 6.2. 硬链接
  • 7. 动静态库
    • 7.1. 静态库
    • 7.2. 动态库
    • 7.3. 动静态库的加载

1. 系统文件I/O

1.1. 接口介绍

在Linux中操作文件,我们可以使用C接口操作,也可以用系统接口来进行文件访问。下面用一段代码介绍一下常见的访问文件的系统接口

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

#define FILE_NAME "log.txt"

int main()
{
    //该进程权限掩码更改为0000
    umask(0);

    //打开一个文件fd,读写,不存在则创建,追加,权限0666
    int fd = open(FILE_NAME, O_RDWR | O_CREAT | O_APPEND, 0666);
    if (fd < 0)
    {
        perror("open");
        return 1;
    }

    int cnt = 5;
    char outBuffer[64];
    //向文件fd追加数据                                                                                                                                                                         
    while (cnt)
    {
        //向outBuffer以特定格式写入数据 "aaaa"
        sprintf(outBuffer, "%s:%d\n", "aaaa", cnt--);
        //向打开的文件fd写入
        write(fd, outBuffer, strlen(outBuffer));
    }
    //重置指针位置
    lseek(fd, 0, SEEK_SET);
    char buffer[1024];
    ssize_t num = read(fd, buffer, sizeof(buffer) - 1);
    if (num > 0) buffer[num] = 0; // 0, '\0', NULL -> 0
    printf("%s", buffer);

    close(fd);
    return 0;
}

运行结果:img

  1. open

man手册查找open的介绍:

img

参数:

img

返回值:

img

img

  1. write

man手册查找write的介绍

img

参数:如上图所示

返回值:写入多少数据就返回多少。

  1. read

img

1.2. 库函数接口与系统接口的关系

库函数接口与系统接口的关系,可以认为是库函数接口对系统接口做了一层封装,供用户使用。如下所示:

img

2. 文件描述符fd

2.1. 0&1&2文件描述符

Linux进程默认情况下会有3个缺省打开的文件描述符,分别是标准输入0, 标准输出1, 标准错误2. 0,1,2对应的物理设备一般是:键盘,显示器,显示器

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

#define FILE_NAME(number) "log.txt"#number

int main()
{
    //打印stdin的文件编号
    printf("stdin->fd: %d\n", stdin->_fileno);
    //打印stdout的文件编号
    printf("stdout->fd: %d\n", stdout->_fileno);
    //打印stderr的文件编号
    printf("stderr->fd: %d\n", stderr->_fileno);

    //打开5个文件
    int fd0 = open(FILE_NAME(1), O_WRONLY | O_CREAT | O_APPEND, 0666);
    int fd1 = open(FILE_NAME(2), O_WRONLY | O_CREAT | O_APPEND, 0666);
    int fd2 = open(FILE_NAME(3), O_WRONLY | O_CREAT | O_APPEND, 0666);
    int fd3 = open(FILE_NAME(4), O_WRONLY | O_CREAT | O_APPEND, 0666);
    int fd4 = open(FILE_NAME(5), O_WRONLY | O_CREAT | O_APPEND, 0666);

    //打印打开文件的文件描述符
    printf("fd: %d\n", fd0);
    printf("fd: %d\n", fd1);
    printf("fd: %d\n", fd2);
    printf("fd: %d\n", fd3);
    printf("fd: %d\n", fd4);

    //关闭文件
    close(fd0);
    close(fd1);
    close(fd2);
    close(fd3);
    close(fd4);

    return 0;
}

运行结果:

img

一个进程可以打开很多文件,当文件被打开了,就需要被管理,管理的本质就是先描述,再组织。所以文件是这样被管理的。如下图所示:

img

2.2. 文件描述符的分配规则

img

如上图所示,默认打开的三个文件流,如果我关闭了0,那么新打开的文件就会从0开始打开。也就是说在files_struct数组当中,找到当前没有被使用的最小的一个下标,作为新的文件描述符。

2.3. 重定向

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


int main()
{
    //关闭stdout
    close(1);
    //打开1个文件
    int fd = open("log.txt", O_WRONLY | O_CREAT | O_TRUNC, 0666);
    if (fd < 0)
    {
        perror("open");
        return 1;
    }
    //打印相关文件描述符
    printf("open fd: %d\n", fd); // printf -> stdout

    //刷新缓冲区
    fflush(stdout);

    //关闭文件
    close(fd);
    return 0;
}

运行结果:

img

原本是在文件描述符3打开的文件,却占用了文件描述符1打开。这种类似重新定义方向的做法,称为重定向。如下图所示:

img

就是原本1的位置的file* 被 3位置的file* 直接覆盖了,使得1位置的file* 改变了方向。

2.4. 重定向系统调用

  1. 输出重定向

操作系统提供了一个系统调用,可以直接实现重定向。

img

其中我们常用就是dup2接口。对应的参数理解,你可以认为是oldfd直接覆盖了newfd,也就是oldfd重新指定了方向。

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{
    //打开1个文件
    int fd = open("log.txt", O_WRONLY | O_CREAT | O_TRUNC, 0666);
    if (fd < 0)
    {
        perror("open");
        return 1;
    }

    //调用系统重定向,把fd重定向到stdin
    //也就是原本显示到显示器上的数据,现在写入到fd中
    dup2(fd,1);
    //打印相关文件描述符
    printf("open fd: %d\n", fd); // printf -> stdout 
                                                                                                                                                                                               
    //刷新缓冲区
    fflush(stdout);

    //关闭文件
    close(fd);
    return 0;
}

运行结果:

img

这种从显示器到文件的重定向叫做输出重定向。

  1. 输入重定向
#include <stdio.h>                                                                                                                                                                             
#include <string.h>    
#include <unistd.h>    
#include <sys/types.h>    
#include <sys/stat.h>    
#include <fcntl.h>    
    
    
int main()    
{    
    //只读方式打开文件    
    int fd = open("log.txt", O_RDONLY);    
    //判断是否打开成功    
    if(fd < 0)    
    {    
        perror("open");    
        return 1;    
    }    
    //输入重定向,也就是说stdin直接读取到fd的内容    
    dup2(fd, 0);    
    
    char line[64];    
    //显示是否读取成功    
    while(1)    
    {    
        printf("> ");    
        if(fgets(line, sizeof(line), stdin) == NULL) break; //stdin->0    
        printf("%s", line);    
    }    
    return 0;    
} 

img

这种从标准输入到文件的重定向叫做输入重定向。

  1. 追加重定向

在输入重定向的基础上,将文件打开的模式增加追加,就可以实现追加重定向。

#include <stdio.h>    
#include <string.h>    
#include <unistd.h>    
#include <sys/types.h>    
#include <sys/stat.h>    
#include <fcntl.h>    
    
    
int main()    
{    
    umask(0);    
    //只写方式,不存在则创建,追加,打开文件    
    int fd = open("log.txt", O_WRONLY | O_CREAT |  O_APPEND, 0666);    
    //判断是否打开成功    
    if(fd < 0)    
    {    
        perror("open");    
        return 1;    
    }    
    //输出重定向,也就是说stdout直接输出到fd    
    dup2(fd, 1);                                                                                                                                                                               
    printf("hello world!\n");    
    printf("hello world!\n");    
    printf("hello world!\n");    
    printf("hello world!\n");    
    fflush(stdout);    
    return 0;    
}    

运行结果:

img

2.5. 进程独立性

子进程的重定向并不会影响父进程img

  1. 有两个进程,一个父进程,一个子进程,操作系统维护着两个task_struct结构体,如上图所示。
  2. 每个进程的PCB中都有一个struct files_struct*的指针files。它们各自指向的struct files_struct结构体中都有一个文件描述符表。
  3. 两个文件描述符表中的内容在子进程刚创建时是一样的,所以它们都指向相同的被打开的文件。
  4. 当子进程将自己文件描述符表中下标为1的文件关闭以后,并不影响父进程文件描述符表中下标为1的数组中的内容。

每个进程都会维护自己的文件描述符表,所以多个进程就会存在多个文件描述符表,但是这些表中的指针指向的被打开文件只有一套。

某个进程进行文件的打开与关闭操作时,只需要修改自己的文件描述符表就可以,不会对其他进程造成任何影响。

3. Linux下一切皆文件

在Linux下一切皆文件,怎么理解呢?先讲讲硬件,如果把硬件看作文件,又该如何理解呢?来看下图:

img

  • 每一个硬件,操作系统都会维护一个struct file类型的结构体,硬件的各种信息都在这个结构体中,并且还有对应读写函数指针(对硬件的操作主要就是读写)。
  • 每个硬件的具体读写函数的实现方式都在驱动层中,使用到相应的硬件时,操作系统会通过维护的结构体中的函数指针调用相应的读写函数。
  1. 站在操作系统的角度来看下层,无论驱动层和硬件层中有什么,在它看来都是struct file结构体,都是通过维护这个结构体来控制各种硬件。
  2. 站在操作系统的角度来看上层,无论用户层以及系统调用有什么,在它看来都是一个个进程,都是一个个的task_struct结构体,都是通过维护这个结构体来调度各个进程的。

真正的文件在操作系统中的体现也是结构体,操作系统维护的同样是被打开文件的结构体而不是文件本身。

一切皆文件是指:在操作系统中一切都是结构体。

4. 缓冲区

4.1. 缓冲区的理解

A在海南,B在黑龙江。A想把自己用过的键盘给B用,那么此时有2种方法可以实现。

  1. A自己一路奔波把键盘给到B手上
  2. A选择一家快递公司,把键盘寄给B

很显然,在现实生活中,绝大多数人都会选择2方案,选择一家快递公司进行邮寄。那么同样的,在计算机世界里,道理也是如此。

img

当你把快递放到快递站的时候,快递站并不会立马就给你寄送过去,而是等到一定的货物量,快递站才会一起寄送快递。这样A就可以在寄送快递这一段时间干自己的事,不用说专门为了给B寄送快递而浪费了自己本来的时间。同样的,计算机世界也是如此,进程给文件发送数据,CPU并不会说专门给文件去发送数据,而其他进程就不管。当进程发送数据给文件时,数据会存放到缓冲区,然后等缓冲区刷新或者缓冲区满发送。

从上面的分析可以得出结论,缓冲区的存在是为了给发送方节省时间。

既然缓冲区的存在是为了给CPU节省时间,那么它的访问速度肯定是比文件要快的多的,所以它只能是内存。所以说,缓冲区本质上就是一段内存。

4.2. 缓冲区的位置

上面讲了缓冲区是一段内存,那么这段内存是谁申请的,它是属于谁的?下面来看一段代码。

img

运行结果:

img

首先可以看到父子进程运行同一段代码,但是只有C接口的代码运行了两次,系统接口的代码只运行了一次。那么就是说缓冲区并不在操作系统内核种。

在C语言中,文件相关的接口都涉及到一个FILE*,那么我们就可以猜测缓冲区就在其中。

img

在Linux源码中,可以看到FILE这个结构体的成员,很多都是在维护缓冲区。所以我们所说的缓冲区都是用户级的缓冲区,都是在用户层面体现出来的。

5. 理解文件系统

5.1. 认识磁盘

如果大家对电脑有过了解,都会知道电脑有个硬件设备叫磁盘,今天我们就来浅浅的认识一下磁盘。

  1. 物理结构

磁盘是电脑的外设,是一个机械结构,相对于CPU而言,它是比较慢的。下图是生活中常见的磁盘。

img

img

可以看到磁盘好似一个圆柱体,其中这个圆柱体是一片一片摞起来的。

  1. 存储结构

img

  • 磁头:向磁盘中读写数据,如上图中有三个盘片,那么就有六个磁头,给它编号从0到5。
  • 柱面:从俯视图中来看,一个盘面可以看做是多个同心圆,每一个同心圆被叫做一个磁道,一叠盘片中的相同磁道所组成的圆柱就这里的柱面,从内到外给柱面编号从0到3。
  • 扇区:在俯视图中,以相同圆心角将盘片分为多个扇形,每个扇形和每个磁道相交产生的区域就被叫做扇区。一个盘面上每个磁道所包含的扇区个数是相同的,同样给每个扇区编号。

每个扇区的大小可以认为是512KB,看似扇区的面积不同,靠近圆心的较小,但是密度大,远离圆心的面积较大,但是密度较小。

这样一来,我们就可以定位任意一个扇区,然后进行读写数据。比如,0号磁头,0号柱面,0号扇区,此时,磁头就会摆动到0号柱面处,当0号磁头对应的盘面中的0号磁道里的0号扇区旋转到磁头位置时,就可以向磁盘中读写数据。

这种定位方法称为CHS定位法。

  1. 逻辑结构

上面的图是不是看起来就像一盘蚊香,假设这个蚊香是可以任意拉伸的。那么我们将这个磁盘拉伸成一条直线,然后将这条直线看成一个数组,数组中的每一个元素就是扇区。

img

此时,磁盘就被我们抽象成了上图所示的数组,并且给每一个扇区进行编号。站在操作系统的角度,操作系统访问这个数组就是在访问磁盘。

那么这个数组的下标是怎么和磁盘的CHS对应起来的呢?

img

如上图所示,可以根据给定的逻辑数组下标转换成CHS定位法,定位到磁盘上具体的某个扇区。

5.2. 文件管理

操作系统看到的磁盘就是一个数组,这个数组每个元素的大小是512K字节(一个扇区),同样我们也知道,每次向磁盘中读写数据都很耗费时间。

  • 为了提高效率,磁头每次访问磁盘的基本单位是4KB(绝大多数情况下)。
  • 即使访问磁盘的一个bit,磁头也是将包过这一个bit在内的周围4KB大小的数据加载到内存。

正因为磁头每次访问的是4KB大小的数据块,所以内存也被划分成了多个4KB大小的空间,每一个空间被叫做页框

同样的,磁盘中的文件,尤其是可执行文件,也被划分成了多个4KB大小的数据块,每一个块被叫做页帧

假设现在有一个500GB大小的磁盘,操作系统如果统一管理的话成本会很高,所以采用分治的思想来管理整个磁盘。

img

  • 将500GB的磁盘分成4个区,只需要管理好一个区,其他三个区便可以复用这套方法。
  • 再将每个区分为多个组,只需要管理好一个组,其他剩下的组便可以复用这套方法,从而管理好这个区。
  • 每个分区以及每个分组是多大要看具体情况。

这种思想有点像递归的思想,所以我们要学习到重点就是如何管理好一个组。

5.3. 分组的管理

img

每个分组中又分为这6个区域。主要了解5个区域

  1. inode Table:存放了这个分组中所有的inode(已经使用的和没有使用的),每个分组中inode的个数是确定的。
  2. inode Bitmap:inode位图,该分组中有多少个inode,这个位图就有多少个bit,并且每一个比特位都与一个inode一一对应。每使用一个inode,对应的位图就会被置1。
  3. Data blocks:保存这该分组内,所有文件的内容,该块区又被分为多个数据块。
  4. Block Bitmap:数据块位图,该分组的Data blocks中有多少个数据块,这个位图就有多少个bit,并且每一个比特位都和一个数据块一一对应。每使用一个数据块,对应的位图就会被置1。
  5. GDT描述表:记录该分组中inode和数据块的使用率等宏观属性。

最主要的是inode这个编号,实际上inode是一个结构体,一个文件的所有属性都在inode中。当创建一个文件的时候,就会在inode Table中申请一个未被使用的inode,并且将对应的位图置1.

  • 文件内容的存储

其中文件内容的存储就存放在Data blocks中,里面有着许多的数据块,并且带有相应的编号。其编号都放在Block中对应起来。

6. 软硬连接

6.1. 软链接

  • 指令:ln -s 要链接的文件名 链接文件名
  • 功能:建立软链接

img

如上图所示,使用红色框中的指令建立了软连接。

  • 建立软连接后,会有新的文件产生。
  • 链接文件和被链接文件的inode不相同,表示链接文件是一个独立的新文件。

链接文件的删除可以用rm删除,也可以用unlink删除,效果是一样的。

  1. 软链接的作用

你可以把在Linux上的软链接类比Windows上的快捷方式。

在当前目录下运行,要补全路径。但是只要我们创建要运行文件的软链接,在当前目录下,只需要运行软链接便可。

img

  1. 软链接与inode无关,只与文件名有关

img

所以删掉链接文件,并不会影响它本身,软链接的指向只是指向一个路径。

6.2. 硬链接

  • 指令:ln 链接文件名 被链接文件名
  • 功能:没有选项-s,建立硬链接

img

inode相同,意味着它俩是一个文件,因为inode是一个文件时唯一标识,而且一个文件只有一个。所以说,硬链接创建的文件并不是一个独立的新文件,它是被链接文件的别名。

硬连接的本质:在指定路径下,新增文件名和inode编号的映射关系!!!

此时就不再是文件名和inode一一对应了,而是一个inode对应多个文件名,这是文件名都标识一个文件,只是叫法不同。

img

上图中,红色框中的数字表示文件的硬连接数,也就是一个inode有几个文件名字和它映射。

  1. 硬链接的删除

rm删除即可。

img

从上图可以得知,删除了硬链接,但是与原来硬链接相同inode的文件依然存在,只是数字减少了1。那么就可以猜测硬链接与链接文件的关系应该如下图所示:

img

在在inode中有一个变量count,它在进行引用计数。

  • 每当一个文件名和这个inode建立映射关系的时候,引用计数加1。
  • 也就是硬连接数每加1,引用计数就加1。

所以在删除这个文件的时候,使用unlink只是让硬链接数和引用计数减了1。只有引用计数减到0,这个文件的inode的位图才会被清0,这个文件才会被删除。

7. 动静态库

简单了解一下动静态库。

  • 动态库:库文件,以.so为后缀(Windows中为.dll)
  • 静态库:库文件,以.a为后缀(Windows中为.lib)
  • 库的命名规则:lib库名.后缀

所以见到一个库,掐头去尾才是它的库名。使用gcc进行编译的时候,默认是采用的动态链接,如果要使用静态链接需要加上选项-static

7.1. 静态库

简单以一个小例子来了解下库是如何形成的。

库源码:

img

头文件:

img

将上诉代码接口给他人使用,并且不想暴露源码,此时我们就可以选择将它制作成库。

  1. 静态库的理解

对源码进行预处理,编译,汇编,形成以.o为后缀的目标文件,就差最后链接一步。

img

img

img

其实库的原理和上面类似,只是将所有的.o为后缀的文件打包在了一起,形成了一个库,在使用的时候直接使用这个库就可以。你可以这么来理解,就是你要给某个顾客打包外卖,顾客吃这个外卖,1是需要勺子,2是需要筷子,3是需要牙签。所以我们将这个外卖所需要的餐具全都打包在一起提供给顾客。

  1. 制作静态库

制作静态库需要用到 ar -rc 库名 所有后缀为.o的文件。

  • 指令:ar -rc libname.a [所有待打包.o]
  • 作用:将所有待打包的.o文件制作成静态库。

img

现在进行如下步骤:

  • 将所用到的头文件全部放在myliba/include目录下。
  • 将静态库文件放在myliba/lib目录下。

img

img

img

此时的静态库已经完成,就是蓝色的目录,此时已经是一个静态库了。

  1. 使用静态库

接下来我们将从使用者的角度来看下静态库该如何使用。

img

如果我们要使用这个库,有两种方法。

    1. 将该静态安装在系统文件中,然后编译的时候,用相应的指令明确是系统中的哪个库即可。
    2. 在编译的时候,用相应的指令明确库的路径,指定库中的文件,然后即可使用,现在来介绍这种用法。

img

选项作用
-I(大写i)指定头文件路径
-L指定库文件路径
-l(小写L)指定库(掐头去尾后的库名)

如上图所示,这样一来,一个第三方库就可以正常使用了。

img

7.2. 动态库

  1. 形成位置无关码

和制作静态库一样,将所有.o文件打包在一起,但不使用ar打包,而是使用gcc来打包。

img

注意,此时是用gcc生成的.o文件,还加了一个选项-fPIC,生成位置无关码。

位置无关码是什么?简单来说就是相对位置。就好比数轴上的数字,1总是在2的旁边。如果想找到1,那么可以从0开始找,也可以直接定位到2的位置,2的旁边便是1。

  1. 形成库文件

img

使用gcc,加-shared选项,告诉gcc生成动态库而不是可执行程序,如上图中红色框中所示。

选项作用
-fPIC生成位置无关码
-shared生成动态库

img

  1. 使用动态库

使用动态库有4种方法。

  1. 将头文件和库文件安装在系统默认搜索路径中(永久)
  • 将头文件复制到/sur/include路径下,将动态库文件安装在/usr/lib64路径下.
  • 并且在编译的时候使用-l选项告诉gcc使用的动态库名称。
  1. 将库文件路径放在环境变量里

img

信息都告诉gcc了,怎么编译不成功呢?

我们将头文件路径,库文件路径,库文件名告诉了gcc。

编译完成以后,和gcc就没有关系了,接下来的执行是操作系统的事情。

那么操作系统就必须得知道所使用的动态库在哪里。

所以接下来的任务就是告诉操作系统我的动态库在哪里。

在执行程序的时候,操作系统会从环境变量LD_LIBRARY_PATH中读取动态库的路径。

将自己的动态库路径放入到环境变量中,再执行刚刚生成的可执行程序,发现可以成功执行了,而且使用的是动态库中的函数接口。

img

这种做法并不能永久生效,因为每次启动shell的时候,它都会从配置文件中重新加载环境变量,我们这里给LD_LIBRARY_PATH赋值只是暂时的。

  1. 将库文件路径放在配置文件中(永久)
  2. 软链接到系统默认搜索路径中(永久)

7.3. 动静态库的加载

  1. 动态库的加载

gcc在编译的时候,只是将库中的库函数生成了一个位置无关码(相对偏移量)放在了程序中,在程序执行的时候,需要操作系统先将整个库加载到内存中,然后再根据位置无关码调用这个库函数。

img

  • 进程被创建以后,将对应的代码加载到内存中。
  • 进程虚拟地址空间的代码段通过页表映射到了内存中,其中就包括生成的位置无关码。
  • 操作系统将指定的动态库也加载到了内存中,由于占据内存空间,所以给它分配了地址。
  • 当进程执行到调用库函数时,操作系统根据位置无关码,在动态库基地址的基础上偏移一定量的地址找到要调用的库函数,并且调用。
  1. 静态库的加载

img

  • 在gcc进行编译时,编译器将要调用的库函数复制到了程序中,形成了可执行程序。
  • 进程被创建后,操作系统将复制了库函数的可执行程序加载到内存中去执行。

静态库的加载和操作系统没有关系,它是编译器完成的,就是将库函数源码复制一份到我们对源码中。

  • 如果使用静态库,同一个库函数被使用了十次,编译器就会在对应位置复制十分,使用100次,就会复制一百次。
  • 如果使用动态库,同一个库函数被使用十次,就会有十个位置无关码,使用100次就会有100个,在执行的时候,操作系统根据偏移量在内存中仅有的一个动态库中调用相应的函数。

所以使用静态库的程序都比使用静态库的程序要大,所占用的内存多。

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

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

相关文章

【通俗易懂】git原理、安装及连接gitlab,github

目录 一、GIT原理【这部分也挺简单&#xff0c;可以看看&#xff0c;如果没时间可以直接跳到第二部分】 SVN与Git的的区别 二、安装Git 2.1 获取Git安装程序 2.2 Git安装过程 三、Git连接Gitlab 3.1 gitlab准备工作 3.2 本地计算机准备工作及配置git 四、Git连接Github…

找不到vcruntime140_1.dll,无法继续执行代码怎么办?5个可以解决的方案分享

在计算机使用过程中&#xff0c;我们经常会遇到一些错误提示&#xff0c;其中之一就是“VCRuntime140_1.dll缺失”。这个错误通常会导致某些应用程序无法正常运行。为了解决这个问题&#xff0c;我们需要进行修复操作。本文将介绍5个修复VCRuntime140_1.dll缺失的方法&#xff…

C语言--判断年月日是否合理

一.题目描述 比如输入2001&#xff0c;2&#xff0c;29&#xff0c;输出&#xff1a; 不合理 。因为平年的二月只有28天 比如输入2000&#xff0c;6&#xff0c;31&#xff0c;输出&#xff1a;不合理。因为6月是小月&#xff0c;只有30天。 二.思路分析 本题主要注意两个问…

物联网AI MicroPython学习之语法 ADC数模模块

学物联网&#xff0c;来万物简单IoT物联网&#xff01;&#xff01; ADC 介绍 模块功能: ADC数模转换模块 ADC功能在ESP32引脚32-39上可用&#xff0c;使用默认配置时&#xff0c;ADC引脚上的输入电压必须介于0.0v和1.0v之间&#xff08;任何高于1.0v的值都将读为4095&#x…

Linux中Team链路聚合配置

目录 一、Team介绍 二、网卡的bonding和Teaming技术 三、Teaming常用工作模式 四、实验环境 五、添加物理网卡 1、给虚拟机新增四张物理网卡 2、查看网卡信息 六、Team链路聚合配置 1、创建team0的网络接口 2、为team0设置静态IP,掩码位&#xff0c;网关&#xff0c;dns…

Bandzip下载(好用的解压缩工具)

1.下载链接&#xff1a;Bandizip - Download Bandizip 6.x 2.点击 下载Bandzip 进行下载&#xff0c;下载到本地&#xff0c;直接安装即可

坑惨啦!!!——符号冲突案例分析

背景 前段时间在北汽项目中&#xff0c;遇到了一个奇怪现象&#xff1a;程序启动之后&#xff0c;偶现运行一段时间后&#xff0c;crash&#xff0c;复现频率较高。困扰了大家较长时间。最终在和同事的不懈努力下&#xff0c;找到的根因&#xff0c;并找到了解决方法。过程中也…

Spring-IOC-@Value和@PropertySource用法

1、Book.java PropertySource(value"classpath:配置文件地址") 替代 <context:property-placeholder location"配置文件地址"/> Value("${book.bid}") Value("${book.bname}") Value("${book.price}") <bean id&…

[羊城杯2020]easyphp .htaccess的利用

[CTF].htaccess的使用技巧总结 例题讲解 掌握知识&#xff1a; 测试发现是阿帕奇服务器&#xff0c;就想到上传文件利用.htaccess配置文件执行jpg文件中的php代码&#xff0c;但是再进行第二次文件写入时会把之前的文件删除掉&#xff0c;所以不能上传两次来利用&#xff0c…

webpack项目 index.html 根据不同的变量引入不同的js

项目 webpack搭建 问题&#xff1a;在入口文件index.html中根据不同的变量引入不同的js 使用插件HtmlWebpackPlugin HtmlWebpackPlugin 项目里用来生成静态文件的 这个插件每个项目基本都要用到的&#xff0c;只要全局搜一下位置 根据配置文件的指令找到执行的文件&#xff0…

openGauss学习笔记-129 openGauss 数据库管理-参数设置-查看参数值

文章目录 openGauss学习笔记-129 openGauss 数据库管理-参数设置-查看参数值129.1 操作步骤129.2 示例 openGauss学习笔记-129 openGauss 数据库管理-参数设置-查看参数值 openGauss安装后&#xff0c;有一套默认的运行参数&#xff0c;为了使openGauss与业务的配合度更高&…

枚举 小蓝的漆房

题目 思路 核心思想是枚举 首先利用set记录每一种颜色 然后依次从set取出一种颜色作为targetColor&#xff0c;遍历房子 如果当前房子的颜色和targetColor不相同&#xff0c;就以当前房子为起点&#xff0c;往后长度为k的区间都涂成targetColor&#xff0c;并且需要的天数递增…

深度学习之基于yolo的体育运动项目姿态估计识别计数系统

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 文章目录 一项目简介 二、功能三、系统四. 总结 一项目简介 深度学习在体育运动项目姿态估计识别计数系统中的应用是一项具有挑战性和应用价值的研究领域。以下是对深度学习在体…

Linux下Centos7 gcc/g++、动态库/静态库(动态/静态链接)

1.gcc/g gcc是对c语言代码进行编译链接&#xff0c;而g是对c代码进行编译链接&#xff0c;接下来我们只对gcc进行讲解&#xff0c;g的使用方法跟gcc是一样的。 编译链接的四个步骤: 1:预处理 2:编译 3:汇编 4:链接 注&#xff1a;这些在后面都会着重讲解 1.1gcc -o 我们先在D…

细节决定成败——我的日志去哪了?

概述 编写本文档的目的有两点。 本周遇到了一个日志丢失的问题&#xff0c;经过分析&#xff0c;觉得挺有意思的。向大家分享一下我的分析及解决思路。应该在很多项目中都会有该问题。领导和我私下讨论过多次&#xff0c;当前的autodomain代码对文件读取的频率太高了,如何去避…

Binlog 太大导致无法解析怎么办?

由于业务写入了一条大事务&#xff0c;导致 MySQL 的 binlog 膨胀。在解析大的 binlog 时&#xff0c;经常会遇到这个问题&#xff0c;导致无法解析&#xff0c;没有其他工具的情况下&#xff0c;很难分析问题。 作者&#xff1a;孙绪宗&#xff0c;新浪微博 DBA 团队工程师&am…

【Python】可再生能源发电与电动汽车的协同调度策略研究

1 主要内容 之前发布了《可再生能源发电与电动汽车的协同调度策略研究》matlab版本程序&#xff0c;本次发布的为Python版本&#xff0c;采用gurobi作为求解器&#xff0c;有需要的可以下载对照学习研究。 首先详细介绍了优化调度模型的求解方案&#xff0c;分别采用二次规划…

透视maven打包编译正常,intellj idea编译失败问题的本质

前言 maven多模块类型的项目&#xff0c;在Java的中大型应用中非常常见&#xff0c; 在 module 很多的情况&#xff0c;经常会出现各种各样的编辑依赖错误问题&#xff0c;今天记录一种比较常见的 case &#xff1a; A 子模块依赖 B 子模块&#xff0c;在 Terminal 上终端上 …

LLM之Prompt(二):清华提出Prompt 对齐优化技术BPO

论文题目&#xff1a;《Black-Box Prompt Optimization: Aligning Large Language Models without Model Training》 论文链接&#xff1a;https://arxiv.org/abs/2311.04155 github地址&#xff1a;https://github.com/thu-coai/BPO BPO背景介绍 最近&#xff0c;大型语言模…

Tomcat 9.0.54源码环境搭建

一. 问什么要学习tomcat tomcat是目前非常流行的web容器&#xff0c;其性能和稳定性也是非常出色的&#xff0c;学习其框架设计和底层的实现&#xff0c;不管是使用、性能调优&#xff0c;还是应用框架设计方面&#xff0c;肯定会有很大的帮助 二. 运行源码 1.下载源…