Linux系统基础-文件系统

个人主页:C++忠实粉丝
欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 C++忠实粉丝 原创

Linux系统基础-文件系统

收录于专栏[Linux学习]
本专栏旨在分享学习Linux的一点学习笔记,欢迎大家在评论区交流讨论💌

目录

1. 回顾C语言文件接口

hello.c 写文件

hello.c 读文件

输出信息到显示器

stdin & stdout & stderr 

总结 

2. 系统文件IO

hello.c写文件

hello.c读文件 

系统接口介绍 

open 

需要的头文件:

 方法:

参数: 

返回值 

系统调用和库函数 

3. 文件描述符fd

0 & 1 & 2

文件系统结构初步了解

文件描述符的分配规则 

重定向

1. > (输出重定向)

2. >> (追加重定向)

3. < (输入重定向)

4. FILE结构体

5. 理解文件系统 

​编辑

 Linux ext2文件系统

硬链接

硬链接的应用: 

软连接

软连接的应用:


1. 回顾C语言文件接口

hello.c 写文件

#include <stdio.h>
#include <string.h>
int main()
{
    FILE *fp = fopen("myfile", "w");
    if(!fp) printf("fopen error!\n");

    const char* msg = "hello C programming language";
    int count = 5;
    while(count--) fwrite(msg, strlen(msg), 1, fp);

    fclose(fp);
    
    return 0;
}

FILE *fp:定义一个指向 FILE 结构的指针 fp,用于处理文件操作。

fopen("myfile", "w"):

尝试以写入模式("w")打开名为 "myfile" 的文件。

如果文件不存在,fopen 会创建一个新的空文件。

如果文件已经存在,内容会被清空。

fwrite(msg, strlen(msg), 1, fp):

msg:要写入的内容。

strlen(msg):要写入的字节数(字符串的长度)。

1:要写入的块数。

fp:目标文件指针。

使用 fclose(fp) 关闭打开的文件,确保所有缓存的内容被写入磁盘,并释放系统资源。

运行结果:

 

注意 :  

在C/C++编程中, 如果打开一个文件后不调用fclose()来关闭它, 可能会导致一下集中后果:

1. 资源泄露'

没打开一个文件, 操作系统都会分配一定的资源(如文件句柄或文件描述符). 如果不关闭文件, 系统的资源将持续占用, 最终可能导致资源耗尽, 无法打开新的文件或进行其他操作, 这种情况在长时间运行的程序或需要频繁打开文件的程序中特别明显(一旦发现, 后果不堪设想~)

2. 数据末写入

文件通常会使用缓冲区来提高写入效率, 在调用fwrite(), fprintf() 等函数时, 数据首先被写入到内存缓冲区中, 而不是立即写入文件, 如果程序在未调用fclose()的情况下终止(例如, 异常, 崩溃或使用exit()), 缓冲区中的数据可能不会被写入到文件中, 从而导致数据丢失~

hello.c 读文件

int main()
{
    FILE* fp = fopen("myfile", "r");
    if(!fp) printf("fopen error!\n");

    char buf[1024];
    const char * msg = "hello linux!\n";
    while(1)
    {
        size_t s = fread(buf, 1, strlen(msg), fp);
        if(s > 0)
        {
            buf[s] = 0;
            printf("%s", buf);
        }
        if(feof(fp)) break;
    }
    fclose(fp);
    return 0;
}

使用 fopen 函数以只读模式("r")打开名为 "myfile" 的文件。如果文件打开失败(如文件不存在),fopen 将返回 NULL,程序会打印错误信息。

while(1) 创建一个无限循环。

使用 fread 函数从文件中读取数据:

第一个参数是目标缓冲区 buf,第二个参数是每次读取的字节大小(1),第三个参数是要读取的字节数(这里是 strlen(msg),即 13 字节)。

如果 fread 成功读取到数据,则 s 将大于 0。

通过 buf[s] = 0; 将读取的数据结尾标志设置为 '\0',以确保后续的 printf 函数正确打印字符串。

然后使用 printf 输出读取到的内容。

使用 feof(fp) 检查文件是否结束,如果是,则跳出循环。

最后关闭打开的文件,释放系统资源。

结果展示:

可以看到, 已经将我们之前写入文件的信息全部打印出来了~ 

输出信息到显示器

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

int main()
{
    const char *msg = "hello fwrite\n";
    fwrite(msg, strlen(msg), 1, stdout);

    printf("hello printf\n");
    fprintf(stdout, "hello fprintf\n");
    return 0;
}

 fwrite 函数用于从内存块写入数据到文件或输出流。

第一个参数是待写入的内存地址,这里是 msg。

第二个参数是每个元素的大小,这里是 strlen(msg),表示字符串的长度(即 14 字节,包括换行符)。

第三个参数是要写入的元素个数,这里为 1,表示写入一个块。

第四个参数是目标输出流,这里是 stdout,标准输出。

printf 是一个格式化输出函数,输出字符串 "hello printf\n" 到标准输出。

fprintf 是一个格式化输出函数,功能与 printf 类似,但可以将输出写入指定的文件流。

第一个参数是目标输出流,这里为 stdout,第二个参数是待输出的字符串。

这行代码的效果与 printf 相同,即将字符串 "hello fprintf\n" 输出到标准输出。

结果展示: 

stdin & stdout & stderr 

C默认会打开三个输入输出流,分别是stdin, stdout, stderr

仔细观察发现,这三个流的类型都是FILE*, fopen返回值类型,文件指针 

我们可以使用man手册直接在linux中查看:

总结 

打开文件的方式:

 

       r      Open text file for reading.  The stream is positioned at the beginning of the file.

       r+     Open for reading and writing.  The stream is positioned at the beginning of the file.

       w      Truncate file to zero length or create text file for writing.  The stream is positioned at the beginning of the file.

       w+     Open for reading and writing.  The file is created if it does not exist, otherwise it is truncated.  The stream is positioned at the beginning of the file.

       a      Open for appending (writing at end of file).  The file is created if it does not exist.  The stream is positioned at the end of the file.

       a+     Open  for reading and appending (writing at end of file).  The file is created if it does not exist.  Output is always appended to the end of the file.  POSIX

              is silent on what the initial read position is when using this mode.  For glibc, the initial file position for reading is at the beginning of  the  file,  but

              for Android/BSD/MacOS, the initial file position for reading is at the end of the file.

翻译后为 : 

1. r  :  打开文件进行阅读, 流位于文件的开头.

2. r+  :  打开读写模拟. 流处于文件的开头位置

3,  w  :  文件截断为零长度或创建用于写入的文本文件, 流被置于文件的开头

4. w+  :  打开文件以供读写, 如果文件不存在, 则创建它; 否则将其截断. 流的位置将设置为文件的开头.

5. a  :  文件处于可追加状态 (可以在文件末尾写入数据). 如果文件不存在, 则创建该文件, 流处于文件末尾的位置.

6. a+  :  用于读取和追加文件 (在文件末尾写入数据), 如果文件不存在, 则会创建文件, 输出始终被追加到文件的末尾  

2. 系统文件IO

操作文件,除了上述C接口(当然,C++也有接口,其他语言也有),我们还可以采用系统接口来进行文件访问, 先来直接以代码的形式,实现和上面一模一样的代码 

hello.c写文件

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

int main()
{
    umask(0);
    int fd = open("myfile", O_WRONLY|O_CREAT, 0644);
    if(fd < 0)
    {
        perror("open");
        return 1;
    }
    int count = 5;
    const char *msg = "hello world!\n";
    int len = strlen(msg);
    while(count--)
    {
        write(fd, msg, len);
    }
    close(fd);
    return 0;
}

umask(0):设置进程的文件模式创建掩码为 0。这意味着后续创建的文件将使用其指定的权限,不受默认掩码的影响。通常情况下,系统会有一个默认的掩码,设置为 0 可以确保文件创建时使用的权限为0644。(可以看到最后我们创建的文件是rw r r, 也就是我们要求的0644)

open 函数用于打开文件。

第一个参数 "myfile" 是要打开或创建的文件名。

第二个参数是打开模式,这里使用了两个标志:

O_WRONLY:以只写模式打开文件。

O_CREAT:如果文件不存在,则创建一个新文件。

这里我使用 | 或起来, 也就以只写模式打开文件, 文件如果不存在就创建一新个文件. 

第三个参数 0644 是文件权限,仅在文件创建时有效。它表示:

所有者具有读写权限(6),

同组用户具有读权限(4),

其他用户也具有读权限(4)。

fd 是返回的文件描述符。如果打开失败,返回值将为负数。

write(fd, msg, len);:

 第一个参数 fd 是文件描述符。

第二个参数 msg 是要写入的内容。

第三个参数 len 是要写入的字节数。

 结果展示:

hello.c读文件 

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

int main()
{
    int fd = open("myfile", O_RDONLY);
    if(fd < 0) 
    {
        perror("open");
        return 1;
    }
    const char* msg = "hello world!\n";
    char buf[1024];
    while(1)
    {
        size_t s = read(fd, buf, strlen(msg));
        if(s > 0) printf("%s", buf);
        else break;
    }
    close(fd);
    return 0;
}

open 函数用于打开文件。

第一个参数 "myfile" 是要打开的文件名。

第二个参数 O_RDONLY 表示以只读模式打开文件。

fd 是返回的文件描述符。如果打开失败,返回值将为负数。

size_t s = read(fd, buf, strlen(msg));:

 使用 read 函数从文件描述符 fd 读取数据。

第一个参数 fd 是文件描述符。

第二个参数 buf 是用来存储读取数据的缓冲区。

第三个参数是 strlen(msg),即读取 msg 字符串的长度(12 字节)。

if(s > 0):

检查返回的字节数 s 是否大于 0。如果大于 0,表示成功读取了数据。

printf("%s", buf);:将缓冲区 buf 中的数据打印到标准输出。

结果展示:

系统接口介绍 

open 

需要的头文件:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
 方法:
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);

pathname: 要打开或创建的目标文件

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

参数: 

O_RDONLY : 只读打开

O_WRONLY: 只写打开

O_RDWR : 读,写打开

                   这三个常量,必须指定一个且只能指定一个

O_CREAT : 若文件不存在,则创建它。需要使用mode选项,来指明新文件的访问权限 O_APPEND: 追加写

返回值 

成功 : 新打开的文件描述符

失败 : -1 

open 函数具体使用哪个,和具体应用场景相关,如目标文件不存在,需要open创建,则第三个参数表示创建文件 的默认权限,否则,使用两个参数的open。 

write, read, close, 了seek, 类比c文件相关接口~ 

系统调用和库函数 

上面的 fopen fclose fread fwrite 都是C标准库当中的函数,我们称之为库函数(libc)。

而, open close read write lseek 都属于系统提供的接口,称之为系统调用接口

如下图所示:

系统调用接口和库函数的关系,一目了然。

所以,可以认为,f#系列的函数,都是对系统调用的封装,方便二次开发。 

3. 文件描述符fd

通过对open函数的学习,我们知道了文件描述符就是一个小整数

0 & 1 & 2

Linux进程默认情况下会有3个缺省打开的文件描述符,分别是标准输入0, 标准输出1, 标准错误2.

0,1,2对应的物理设备一般是:键盘,显示器,显示器

所以输入输出还可以采用如下方式: 

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

int main()
{
    char buf[1024];
    size_t s = read(0, buf, sizeof(buf));
    if(s > 0)
    {
        buf[s] = 0;
        write(1, buf, strlen(buf));
        write(2, buf, strlen(buf));
    }
    return 0;
}

read(0, buf, sizeof(buf));:使用 read 函数从标准输入(文件描述符 0)读取数据。

第一个参数 0 表示从标准输入读取。

第二个参数 buf 是用于存储读取数据的缓冲区。

第三个参数 sizeof(buf) 表示读取的最大字节数(即 1024 字节)。

write(1, buf, strlen(buf));:

使用 write 函数将 buf 中的数据写入标准输出(文件描述符 1)。

strlen(buf) 计算 buf 中的字符串长度,以确保写入的字节数正确。

write(2, buf, strlen(buf));:

同样使用 write 函数将 buf 中的数据写入标准错误(文件描述符 2)。

注意:标准输出和标准错误是两个不同的输出流,通常在终端中显示在同一位置,但在文件重定向时,可以分开处理。

结果展示:

文件系统结构初步了解

根据以上我们的分析, 可以得到文件系统的初步结构, 如下图:

 

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

文件描述符的分配规则 

代码示例:

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

int main()
{
    int fd = open("myfile", O_RDONLY);
    if(fd < 0)
    {
        perror("open");
        return 1;
    }
    printf("fd: %d\n", fd);
    close(fd);
    return 0;
}

输出发现是 fd: 3 

关闭0或者2,在看:

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

int main()
{
    close(0);
    int fd = open("myfile", O_RDONLY);
    if(fd < 0)
    {
        perror("open");
        return 1;
    }
    printf("fd: %d\n", fd);
    close(fd);
    return 0;
}

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

int main()
{
    close(2);
    int fd = open("myfile", O_RDONLY);
    if(fd < 0)
    {
        perror("open");
        return 1;
    }
    printf("fd: %d\n", fd);
    close(fd);
    return 0;
}

发现是结果是: fd: 0 或者 fd 2 可见,文件描述符的分配规则:在files_struct数组当中,找到当前没有被使用的 最小的一个下标,作为新的文件描述符. 

重定向

那如果关闭1呢?看代码:

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

int main()
{
    close(1);
    int fd = open("myfile", O_WRONLY | O_CREAT, 00644);
    if (fd < 0)
    {
        perror("open");
        return 1;
    }
    printf("fd: %d\n", fd);
    fflush(stdout);

    close(fd);
    exit(0);
}

此时,我们发现,本来应该输出到显示器上的内容,输出到了文件 myfile 当中,其中,fd=1。这种现象叫做输出重定向。常见的重定向有:>, >>, <

例如: 

1. > (输出重定向)

> 符号用于将命令的标准输出重定向文件, 如果文件已经存在, 则会被覆盖 (如果目标文件已经存在, 则其内容会被覆盖~~)

2. >> (追加重定向)

>> 符号用于将命令的标准输出追加到文件的末尾, 如果目标文件不存在, 则会创建该文件 

3. < (输入重定向)

 < 符号用于将文件的内容作为命令的标准输入, 它可以将文件的内容传递给命令, 而不是从键盘输入~

4. FILE结构体

因为IO相关函数与系统调用接口对应,并且库函数封装系统调用,所以本质上,访问文件都是通过fd访问的。 所以C库当中的FILE结构体内部,必定封装了fd 

来段代码在研究一下:

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


int main()
{
    const char* msg0 = "hello printf\n";
    const char* msg1 = "hello fwrite\n";
    const char* msg2 = "hello write\n";

    printf("%s", msg0);
    fwrite(msg1, strlen(msg1), 1, stdout);
    write(1, msg2, strlen(msg2));

    fork();

    return 0;
}

运行出结果: 

 但如果对进程实现输出重定向呢? ./hello > file , 我们发现结果变成了:

我们发现 printf 和 fwrite (库函数)都输出了2次,而 write 只输出了一次(系统调用)。为什么呢?肯定和 fork有关!

一般C库函数写入文件时是全缓冲的,而写入显示器是行缓冲。

printf fwrite 库函数会自带缓冲区,当发生重定向到普通文件时,数据的缓冲方式由行缓冲变成了全缓冲。

而我们放在缓冲区中的数据,就不会被立即刷新,甚至fork之后

但是进程退出之后,会统一刷新,写入文件当中。

但是fork的时候,父子数据会发生写时拷贝,所以当你父进程准备刷新的时候,子进程也就有了同样的 一份数据,随即产生两份数据。

write 没有变化,说明没有所谓的缓冲 

综上: printf fwrite 库函数会自带缓冲区,而 write 系统调用没有带缓冲区。另外,我们这里所说的缓冲区, 都是用户级缓冲区。其实为了提升整机性能,OS也会提供相关内核级缓冲区,不过不再我们讨论范围之内。

那这个缓冲区谁提供呢? printf fwrite 是库函数, write 是系统调用,库函数在系统调用的“上层”, 是对系统 调用的“封装”,但是 write 没有缓冲区,而 printf fwrite 有,足以说明,该缓冲区是二次加上的,又因为是 C,所以由C标准库提供 

5. 理解文件系统 

经过上面的铺垫, 现在我们正式认识一下LinuxOS下的文件系统:
我们使用ls -l的时候看到的除了看到文件名,还看到了文件元数据 

每行包含7列:

1. 模式 2. 硬链接数 3. 文件所有者 4, 组 5, 大小 6. 最后修改时间 7. 文件名

ls -l读取存储在磁盘上的文件信息,然后显示出来 

 其实这个信息除了通过这种方式来读取,还有一个stat命令能够看到更多信息

我们可以看到text.c文件上面有Inode, 为了能解释清楚inode我们先简单了解一下文件系统 

 Linux ext2文件系统

 如下图所示:

Linux ext2文件系统,上图为磁盘文件系统图(内核内存映像肯定有所不同),磁盘是典型的块设备,硬盘分区被划分为一个个的block。一个block的大小是由格式化的时候确定的,并且不可以更改。例如mke2fs的-b选项可以设 定block大小为1024、2048或4096字节。而上图中启动块(Boot Block)的大小是确定的, 

对上面名词的解释:

1. Block Group:ext2文件系统会根据分区的大小划分为数个Block Group。而每个Block Group都有着相同的结构组成。政府管理各区的例子

2. 超级块(Super Block):存放文件系统本身的结构信息。记录的信息主要有:bolck 和 inode的总量, 未使用的block和inode的数量,一个block和inode的大小,最近一次挂载的时间,最近一次写入数据的时间,最近一次检验磁盘的时间等其他文件系统的相关信息。Super Block的信息被破坏,可以说整个文件系统结构就被破坏了

3. GDT,Group Descriptor Table:块组描述符,描述块组属性信息,有兴趣的同学可以在了解一下

4. 块位图(Block Bitmap):Block Bitmap中记录着Data Block中哪个数据块已经被占用,哪个数据块没有被占用

5. inode位图(inode Bitmap):每个bit表示一个inode是否空闲可用。

6. i节点表:存放文件属性 如文件大小,所有者,最近修改时间等

7. 数据区:存放文件内容

将属性和数据分开存放的想法看起来很简单,但实际上是如何工作的呢?我们通过touch一个新文件来看看如何工作。 

 

创建一个新文件主要有一下4个操作:

1. 存储属性 内核先找到一个空闲的i节点(这里是528160)。内核把文件信息记录到其中。 2. 存储数据 该文件需要存储在三个磁盘块,内核找到了三个空闲块:300, 500, 800。将内核缓冲区的第一块数据复制到300,下一块复制到500,以此类推。

3. 记录分配情况 文件内容按顺序300,500,800存放。内核在inode上的磁盘分布区记录了上述块列表。

4. 添加文件名到目录 

新的文件名abc。linux如何在当前的目录中记录这个文件?内核将入口(528160,abc)添加到目录文件。文件名和inode之间的对应关系将文件名和文件的内容及属性连接起来。 

文件名和inode编号具有映射关系!!

1. 一个目录下不能建立同名文件

2. 查找文件的顺序 : 文件名 -> inode编号

总结 : 

文件 = 内容 + 属性(也是数据)

文件在磁盘存储 本质是: 文件的内容 + 文件的属性数据

Linux文件系统特定: 文件内容 和 文件属性 分开存储

找到指定的文件 -> 文件所在目录(目录也是文件) -> 根据文件名 ->(映射) inode -> 目标文件

硬链接

我们看到,真正找到磁盘上文件的并不是文件名,而是inode。 其实在linux中可以让多个文件名对应于同一个 inode。 

 

abc和def的链接状态完全相同,他们被称为指向文件的硬链接。内核记录了这个连接数,inode 528160的硬连接数为2。

我们在删除文件时干了两件事情:

1.在目录中将对应的记录删除,

2.将硬连接数-1,如果为0,则将对应的磁盘释放。 

总结 : 硬链接不是一个独立的文件, 因为你没有独立的inode number, 你用的是目标文件的inode

硬链接就是一个文件名和inode的映射关系, 建立硬链接, 就是在指定目录下, 添加一个新的文件名和inode number的映射关系! 

硬链接的应用: 

任何一个目录, 刚开始新建的时候, 引用计数一定是2:

目录1内部, 新建一个目录, 会让1目录的引用计数自动+1, 一个目录内部有几个目录 : 1引用计数-2

所以我们可以使用cd .. cd .进行路径访问

 

总结: 

数据冗余:在不占用额外空间的情况下创建多个引用。
保护数据:如果删除了某个硬链接,文件内容仍然存在,只要还有其他硬链接指向该 inode。(一般常用硬链接做备份)
方便访问:可以使用不同的名字或路径访问同一个文件。

软连接

硬链接是通过inode引用另外一个文件,软链接是通过名字引用另外一个文件,在shell中的做法为:

软链接是一种指向另一个文件路径的引用,类似于 Windows 系统中的快捷方式。它包含原始文件的路径信息,而不是直接指向文件数据。(所以大家别再认为删除桌面快捷方式就是把软件彻底删除了, 实际上你删除是它的软连接而已, 里面只有它的路径, 没有数据)

软连接的应用:

总结 :

简化路径:使用软链接可以简化复杂路径的访问。(快捷方式)
文件版本管理:可以为不同版本的文件创建软链接,方便切换。
跨文件系统的引用:可以在不同文件系统之间链接文件。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

RabbitMQ进阶_可靠性

文章目录 一、 发送者的可靠性1.1、 生产者重试机制1.2、 生产者确认机制1.2.1、确认机制理论1.2.2、确认机制实现1.2.2.1、定义ReturnCallback1.2.2.2、定义ConfirmCallback 二、 MQ的可靠性2.1、 数据持久化2.1.1、 交换机持久化2.1.2、 队列持久化2.1.3、 消息持久化 2.2、 …

R语言机器学习算法实战系列(四)随机森林算法+SHAP值 (Random Forest)

禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 文章目录 介绍教程下载数据加载R包导入数据数据预处理数据描述特征选择数据切割调节参数构建模型预测测试数据评估模型模型准确性混淆矩阵模型评估指标ROC CurvePRC Curve特征的重要性模型解释保…

C#/.NET/.NET Core技术前沿周刊 | 第 9 期(2024年10.07-10.13)

前言 C#/.NET/.NET Core技术前沿周刊&#xff0c;你的每周技术指南针&#xff01;记录、追踪C#/.NET/.NET Core领域、生态的每周最新、最实用、最有价值的技术文章、社区动态、优质项目和学习资源等。让你时刻站在技术前沿&#xff0c;助力技术成长与视野拓宽。 欢迎投稿、推荐…

MinIO快速入门:开启你的文件存储之旅

在现代应用中&#xff0c;文件存储服务是至关重要的组件之一。像腾讯云的COS&#xff08;对象存储服务&#xff09;等云存储服务提供了丰富的功能&#xff0c;但随之而来的云端费用也是开发者无法忽视的问题。本文将介绍一款开源、高性能的对象存储服务——MinIO&#xff0c;它…

【含开题报告+文档+PPT+源码】基于SSM框架的诗词吟诵知识学习系统的设计与实现

开题报告 随着信息技术的迅猛发展和互联网的普及&#xff0c;在线教育逐渐成为现代教育的重要形式。在线学习平台以其便捷性、灵活性和个性化等特点&#xff0c;受到广大师生的青睐。特别是在线吟诵知识学习&#xff0c;已经成为许多学生提升自我修养、陶冶情操的重要途径。青…

基于华为云CodeArts Repo和流水线门禁的分支合并与部署

本文分享自华为云社区《【开发者空间实践】基于Repo和流水线门禁的分支合并与部署-云社区-华为云》 一、案例介绍 流水线&#xff08;CodeArts Pipeline&#xff09;提供可视化、可编排的CI/CD持续交付软件生产线&#xff0c;帮助企业快速转型&#xff0c;实现DevOps持续交付高…

FastApi SQLAlchemy SQLite

FastApi fastapi是一个用于构建API 的现代、快速&#xff08;高性能&#xff09;的web框架&#xff0c;它是建立在Starlette和Pydantic基础上的。 Pydantic是一个基于Python类型提示来定义数据验证、序列化和文档的库&#xff0c;Starlette是一种轻量级的ASGI框架/工具包&…

Qt编写的modbus模拟器/支持网络和串口以及websocket/支持网络rtu

一、使用说明 1.1 设备模拟-Com 第一步&#xff0c;填写要模拟的设备地址&#xff0c;0表示自动处理&#xff0c;也就是收到什么地址就应答什么地址。第二步&#xff0c;填写对应的串口号和波特率。第三步&#xff0c;单击打开串口&#xff0c;成功后会变成关闭串口字样。单击…

智慧公厕厂家:智慧公厕建设推动城市公厕智能化变革

随着科技的不断进步&#xff0c;智慧公厕厂家正以创新之力推动着城市公厕的智能化变革。 一、提升用户体验 智慧公厕为使用者带来了前所未有的便利。通过实时显示厕位使用情况&#xff0c;避免了旅客的无效排队&#xff0c;节省了时间。感应式设备如水龙头、洗手液等&#xff…

工业数据采集网关如何与设备进行连接?天拓四方

在工业自动化与智能化日益普及的今天&#xff0c;工业数据采集网关成为了连接各种工业设备与数据中心的桥梁。 一、工业数据采集网关的作用 工业数据采集网关&#xff0c;作为工业自动化系统的核心组成部分&#xff0c;负责实时采集、处理和传输来自各种工业设备的数据。它能…

RS232和RS485

文章目录 RS232和RS485编程与UART一摸一样RS232RS485 前情提要&#xff1a;UART的缺点 电气接口不统一 UART只是对信号的时序进行了定义&#xff0c;而未定义接口的电气特性 电压电平不兼容 UART通信中通常使用处理器的电平&#xff08;如TTL电平&#xff09;&#xff0c;但不…

【Vue】Vue3.0(十三)中标签属性ref(加在普通标签上、加在组件标签上)、局部样式

上篇文章&#xff1a; 【Vue】Vue3.0 &#xff08;十二&#xff09;、watchEffect 和watch的区别及使用 &#x1f3e1;作者主页&#xff1a;点击&#xff01; &#x1f916;Vue专栏&#xff1a;点击&#xff01; ⏰️创作时间&#xff1a;2024年10月18日20点56分 文章目录 基本…

主键 外键

主键 外键 在关系型数据库中&#xff0c;主键&#xff08;Primary Key&#xff09;和外键&#xff08;Foreign Key&#xff09;是用于维护数据完整性和建立表之间关系的重要概念。 主键&#xff08;Primary Key&#xff09; 定义: 主键是一个或多个列的组合&#xff0c;其值能…

初始Python篇(4)—— 元组、字典

找往期文章包括但不限于本期文章中不懂的知识点&#xff1a; 个人主页&#xff1a;我要学编程(ಥ_ಥ)-CSDN博客 所属专栏&#xff1a; Python 目录 元组 相关概念 元组的创建与删除 元组的遍历 元组生成式 字典 相关概念 字典的创建与删除 字典的遍历与访问 字典…

Maple :一款强大的计算软件,广泛应用于数学、工程、物理和其他科学领域

Maple 是一款强大的计算软件&#xff0c;广泛应用于数学、工程、物理和其他科学领域。它以其符号计算、数值计算和图形可视化能力而闻名&#xff0c;适用于从基础到高级的数学问题。以下是对 Maple 的详细介绍&#xff1a; 1. 基本功能 符号计算 &#xff1a;Maple 能够处理复…

RBAC 模型

系统权限控制最常采用的访问控制模型就是 RBAC 模型 。 什么是 RBAC 呢&#xff1f; RBAC 即基于角色的权限访问控制&#xff08;Role-Based Access Control&#xff09;。这是一种通过角色关联权限&#xff0c;角色同时又关联用户的授权的方式。 简单地说&#xff1a;一个用…

鸿蒙网络编程系列7-TLS安全数据传输单向认证示例

1.TLS简介 TLS&#xff08;Transport Layer Security&#xff09;协议的前身是SSL&#xff08;Secure Socket Layer&#xff09;安全套接层协议&#xff0c;由Netscape公司于1994年提出&#xff0c;是一套网络通信安全协议。IETF&#xff08;The Internet Engineering Task Fo…

ORACLE 19C安装 RAC报错

1. 问题描述 在Oracle 19C RAC的安装过程中&#xff0c;使用克隆方式在两个节点上部署集群。当第一个节点配置好基础服务后&#xff0c;关机并克隆节点。当尝试在第二个节点上通过页面进行RAC安装时&#xff0c;出现以下错误&#xff1a; [INS-32070] Could not remove the n…

Maven--简略

简介 Apache旗下的一款开源项目&#xff0c;用来进行项目构建&#xff0c;帮助开发者管理项目中的jar及jar包之间的依赖&#xff0c;还拥有项目编译、测试、打包的功能。 管理方式 统一建立一个jar仓库&#xff0c;把jar上传至统一的仓库&#xff0c;使用时&#xff0c;配置…