Linux系统编程-文件系统

目录

什么是Linux文件系统

文件系统的职责

存储介质抽象

inode:文件系统的核心

文件分配策略

目录结构

文件系统布局

日志和恢复机制

目录权限

粘滞位(t位):

硬链接和符号链接

硬链接的特点:

创建硬链接:

符号链接的特点:

创建符号链接:

文件属性

1.stat

2.fstat

3.lstat

4.chmod&fchmod

目录操作

目录的创建和销毁

更改当前工作路径

目录流操作

日期和时间

1.time

2.gmtime

3.localtime

4.strftime

 /etc目录下的文件

/etc/passwd

etc/group

/etc/shadow

GLOB函数

利用glob实现du功能

利用glob实现shell的ls功能


什么是Linux文件系统

        在操作系统的世界中,文件系统扮演着至关重要的角色,它负责管理磁盘上的数据,提供数据持久化和访问的机制。Linux文件系统,以其强大的灵活性和高性能,成为了许多系统管理员和开发者的首选。本文将从底层角度,深入探讨Linux文件系统的内部工作原理。

文件系统的职责

        首先,让我们明确文件系统的基本职责:

        1. 数据持久化:将数据从易失性的内存转移到非易失性的存储介质上。
        2. 数据访问:提供一种机制,允许用户和应用程序读取和写入数据。
        3. 数据组织:以一种逻辑和层次化的方式组织数据,通常以目录和文件的形式呈现。

存储介质抽象

        Linux文件系统将物理存储介质抽象为逻辑存储单元,这个过程涉及到几个关键概念:

        块设备:文件系统通过块设备接口与磁盘交互,块设备提供了一个统一的接口来处理不同类型存储设备的I/O操作。
        缓冲区:为了提高I/O效率,文件系统使用缓冲区暂存即将写入磁盘或从磁盘读取的数据。

inode:文件系统的核心

        每个文件或目录在Linux文件系统中都有一个对应的inode(索引节点)。inode包含了文件的元数据,而不是文件的数据本身。这包括:

        文件大小
        权限(所有者、组、其他)
        时间戳(创建、访问、修改时间)
        数据块索引

文件分配策略

        文件系统需要决定如何将文件数据分配到磁盘上的数据块。这涉及到多种文件分配策略:

        连续分配:在早期的文件系统中使用,将文件数据存储在连续的磁盘块中。
        链式分配:每个数据块包含指向下一个数据块的指针。
        索引分配:使用一个索引块来记录数据块的位置。

        现代文件系统,如Ext4和XFS,采用更为复杂的分配策略,以提高性能和灵活性。

目录结构

        Linux文件系统的目录结构由目录项(Dentry)实现,每个目录项包含:

        文件或目录的名称
        指向对应inode的指针
        这种结构使得文件和目录的查找变得非常高效。

文件系统布局

        在磁盘上,文件系统的布局通常包括:

        超级块:包含文件系统的全局信息,如块大小、inode数量等。
        inode表:存储所有inode的区域。
        数据块区:存储文件数据的区域。

日志和恢复机制

        现代文件系统使用日志来记录文件系统的操作,这有助于在系统崩溃后恢复文件系统的状态。例如,Ext4文件系统使用journaling来保证数据的一致性。


目录权限

        在Linux中,目录权限通常以10个字符的字符串表示,例如-drwxrwxrwt。这个字符串从左到右的含义如下:

第一个字符:
    d:目录(directory)。
    -:普通文件(regular file)。
    l:符号链接(symbolic link)。
    b:块设备文件(block device)。
    c:字符设备文件(character device)。
    p:管道文件(named pipe,FIFO)。
    s:套接字文件(socket)
接下来的三组字符(每组三个字符)
    第一组表示所有者的权限(owner)。
    第二组表示与所有者同一组的用户的权限(group)。
    第三组表示其他所有用户的权限(others)。
    其中r(4)表示可读,w(2)可写,x(1)可执,s表示权限切换user
特殊权限位:
    如果在第三组权限的末尾有一个 t,则表示设置了粘滞位


粘滞位(t位):

        在Linux系统中通常被称为 "t" 位,是一种特殊的文件系统权限位,它对目录的行为有特定的影响。当对目录设置了粘滞位后,只有该目录的拥有者和文件的所有者才能删除或者重命名目录中的文件。


粘滞位的主要作用:
    1.防止删除和重命名:如果一个目录设置了粘滞位,那么只有文件的所有者和目录的所有者可以删除或者重命名该目录下的文件。这可以防止普通用户删除或重命名其他用户在该目录下的文件。
    2.保护公共目录:粘滞位通常用于公共目录,如 /tmp,以确保用户可以创建临时文件,但不能删除或重命名其他用户的临时文件。


如何设置粘滞位:
        在Linux系统中,可以通过 chmod 命令来设置粘滞位。设置粘滞位的命令格式如下:

chmod +t <directory>

硬链接和符号链接

        硬链接(Hard Link)是一种文件链接方式,它直接指向文件的数据所在的位置,即文件系统中的inode(索引节点)。硬链接不是文件的副本,它与原始文件共享相同的inode和数据块。这意味着硬链接和原始文件是完全相同的,对硬链接的修改实际上是对原始文件的修改,反之亦然。硬链接在文件系统管理、备份和数据恢复等场景中非常有用,因为它们提供了对原始数据的直接访问,而不需要复制数据。然而,由于硬链接的特性,使用时也需要谨慎,以避免意外覆盖或删除重要文件。可以使用stat查询Links数,即inode硬链接数量。

硬链接的特点:

        1.共享inode:硬链接共享相同的inode和数据块,因此它们具有相同的inode号。
        2.文件名无关:硬链接可以位于不同的目录中,与文件名无关。硬链接的创建不会影响文件的目录结构。
        3.不可跨文件系统:硬链接不能跨越不同的文件系统创建。硬链接必须位于与原始文件相同的文件系统中。
         4.删除行为:只有当指向同一个inode的所有硬链接都被删除后,文件的数据才会被系统释放。删除硬链接不会删除原始文件或其它硬链接。
         5.不适用于目录和分区:硬链接通常不用于目录,因为目录的硬链接可能导致文件系统中的循环,从而引发问题。

创建硬链接:

        在Linux中,可以使用 ln 命令创建硬链接,命令格式如下:

ln existing_file new_link

        这里的 existing_file 是已存在的文件,new_link 是要创建的硬链接的名称。


        符号链接(Symbolic Link,也称为Symlink)是一种特殊的文件类型,它包含了指向另一个文件或目录的路径。符号链接可以视为一个快捷方式,它允许用户通过链接访问目标文件或目录,就像直接访问原始文件或目录一样。
Blocks为0不占内存空间

符号链接的特点:

    1.包含路径:符号链接是一个单独的文件,包含了指向另一个文件或目录的路径。
    2.跨文件系统:符号链接可以跨越不同的文件系统,这与硬链接不同。
    3.目录和文件:符号链接可以指向文件或目录。
    4.删除独立性:删除符号链接不会影响它所指向的原始文件或目录。
    5.更新和移动:如果原始文件或目录被移动或重命名,符号链接将变为死链接(dangling symlink),即它指向的路径不再有效。
    6.权限继承:符号链接的权限与原始文件或目录的权限无关,但访问符号链接时的权限检查会应用到目标文件或目录。

创建符号链接:

        在Linux中,可以使用 ln 命令的 -s 选项创建符号链接,命令格式如下:

 ln -s target_path link_name

        这里的 target_path 是要链接的目标文件或目录的路径,link_name 是符号链接的名称。


文件属性

1.stat

int stat(const char *pathname, struct stat *statbuf);

        通过文件路径获取属性信息填入 struct stat中,成功返回0,失败返回-1

2.fstat

int fstat(int fd, struct stat *statbuf);

        通过文件描述符获取属性信息填入 struct stat中,成功返回0,失败返回-1

3.lstat

int lstat(const char *pathname, struct stat *statbuf);struct stat {dev_t st_dev;         /* 包含文件的设备的ID */ino_t st_ino;         /* inode(索引节点)编号 */mode_t st_mode;       /* 16位的位图,表示文件类型,文件访问权限,特殊权限位 */nlink_t st_nlink;     /* 硬链接的数量 */uid_t st_uid;         /* 所有者的用户名ID */gid_t st_gid;         /* 所有者的组ID */dev_t st_rdev;        /* 特殊文件的设备ID */off_t st_size;        /* 总大小,单位为字节 */blksize_t st_blksize; /* 文件系统I/O的块大小 */blkcnt_t st_blocks;  /* 分配的512B块的数量 *//* 自 Linux 2.6 起,内核支持以下时间戳字段的纳秒级精度。有关 Linux 2.6 之前的详细信息,请参阅注释。 */struct timespec st_atim;  /* 最后访问时间 */struct timespec st_mtim;  /* 最后修改时间 */struct timespec st_ctim;  /* 最后状态改变时间 */#define st_atime st_atim.tv_sec      /* 向后兼容 */#define st_mtime st_mtim.tv_sec#define st_ctime st_ctim.tv_sec
};

        面对符号链接文件时获取的是符号链接文件的属性。

4.chmod&fchmod

int chmod(const char *pathname, mode_t mode);
int fchmod(int fd, mode_t mode);

        改变权限,成功返回0,失败-1
S_ISUID  (04000)  设置用户ID(在调用 execve(2) 时设置进程有效用户ID)
S_ISGID  (02000)  设置组ID(在调用 execve(2) 时设置进程有效组ID;强制性锁定,如 fcntl(2) 中所述;从父目录获取新文件的组,如 chown(2) 和 mkdir(2) 中所述)
S_ISVTX  (01000)  粘滞位(限制删除标志,如 unlink(2) 中所述)
S_IRUSR  (00400)  所有者读取
S_IWUSR  (00200)  所有者写入
S_IXUSR  (00100)  所有者执行/搜索("搜索"适用于目录,意味着可以访问目录内的条目)
S_IRGRP  (00040)  组内成员读取
S_IWGRP  (00020)  组内成员写入
S_IXGRP  (00010)  组内成员执行/搜索
S_IROTH  (00004)  其他用户读取
S_IWOTH  (00002)  其他用户写入
S_IXOTH  (00001)  其他用户执行/搜索


目录操作

目录的创建和销毁

int mkdir(const char *pathname, mode_t mode);

        创建一个新目录。如果目录的父目录不存在,或者没有足够的权限,函数将失败。

int rmdir(const char *pathname);

        删除一个空目录。如果目录非空,或者指定路径不存在,或者没有足够的权限,函数将失败。

更改当前工作路径

int chdir(const char *path);

        改变(切换)当前工作目录到指定的路径。如果路径不存在或没有足够的权限访问该路径,函数将失败。

int fchdir(int fd);

          改变当前工作目录到由文件描述符 fd 指向的目录。

char *getcwd(char *buf, size_t size);

         获取当前工作目录的绝对路径,并将其复制到由 buf 指向的缓冲区中。如果缓冲区大小不足以存储路径,函数将失败。

目录流操作

DIR *opendir(const char *name);
DIR *fdopendir(int fd);

        打开文件夹获取DIR流指针,失败返回NULL

struct dirent *readdir(DIR *dirp);struct dirent {ino_t d_ino;       /* inode编号 */off_t d_off;       /* 并非偏移量;详见下文 */unsigned short d_reclen; /* 此记录的长度 */unsigned char d_type; /* 文件类型;并非所有文件系统类型都支持 */char d_name[256]; /* 以空字符结尾的文件名 */};

        返回指向struct dirent指针,dirent里存储了目录的信息,失败返回空指针


日期和时间

1.time

time_t time(time_t *tloc);

        时间戳是从 1970 年 1 月 1 日(UTC 时间)开始计算的Unix 时间戳,tloc如果提供了这个参数,函数会将当前时间的时间戳存储在这个指针指向的位置。如果这个参数是 NULL 或者没有提供,函数不会写入任何值。

2.gmtime

struct tm *gmtime(const time_t *timep);struct tm {int tm_sec;    /* Seconds (0-60) */int tm_min;    /* Minutes (0-59) */int tm_hour;   /* Hours (0-23) */int tm_mday;   /* Day of the month (1-31) */int tm_mon;    /* Month (0-11) */int tm_year;   /* Year - 1900 */int tm_wday;   /* Day of the week (0-6, Sunday = 0) */int tm_yday;   /* Day in the year (0-365, 1 Jan = 0) */int tm_isdst;  /* Daylight saving time */
};

        Unix时间转为tm结构体,该结构体表示的是协调世界时UTC

3.localtime

struct tm *localtime(const time_t *timep);

        Unix时间转为tm结构体,会根据本地时区和夏令时调整来转换时间

4.strftime

size_t strftime(char *s, size_t max, const char *format, const struct tm *tm);

        根据给定的格式字符串,将 tm 结构体中的时间信息格式化为可读的字符串,并将其存储在提供的字符数组 s 中


参数
    s:指向字符数组的指针,用于存储格式化后的字符串。
    max:s 数组的最大长度,即可以存储的最大字符数,包括空字符('\0')。
    format:一个格式字符串,指定了时间的格式化方式。格式字符串中可以包含特殊的格式说明符,如 %Y 表示四位数的年份等。
    tm:指向 tm 结构体的指针,包含了要格式化的时间信息。

返回值
    函数返回实际写入到 s 数组中的字符数(不包括结尾的空字符)。如果由于缓冲区大小不足而无法写入整个字符串,返回值会小于 max。如果 s 是 NULL 或 max 是 0,则函数不执行格式化操作,但仍然会返回需要的缓冲区大小(不包括结尾的空字符)。

格式化说明符
    %a:缩写的星期名称。
    %A:完整的星期名称。
    %b:缩写的月份名称。
    %B:完整的月份名称。
    %c:适合人类可读的日期和时间。
    %d:月份中的第几天(01-31)。
    %H:小时(24小时制,00-23)。
    %I:小时(12小时制,01-12)。
    %m:月份(01-12)。
    %M:分钟(00-59)。
    %S:秒(00-59)。
    %Y:四位数的年份。


 /etc目录下的文件

/etc/passwd

        文件中的每行都包含一个用户账户的信息,字段之间用冒号(:)分隔。标准的字段包括:

        -用户名:用户的登录名。
        -密码:通常是一个“x”字符,表示密码存储在 /etc/shadow 文件中,或者是加密后的密码散列值。
        -用户ID(UID):用户的唯一标识符,通常是数字。
        -组ID(GID):用户所属主组的唯一标识符。
        -主目录:用户的主目录路径。
        -登录shell:用户登录时使用的 shell。

格式示例如下:
    username:x:UID:GID:User Name:/home/username:/bin/bash

具体解释如下:
    username:用户的登录名。
    x:表示密码存储在 /etc/shadow 文件中。
    UID:用户的唯一标识符。
    GID:用户所属主组的唯一标识符。
    User Name:用户的全名或描述。
    /home/username:用户的主目录路径。
    /bin/bash:用户的默认登录 shell。

struct passwd *getpwnam(const char *name);struct passwd {char   *pw_name;       /* username */char   *pw_passwd;     /* user password */uid_t   pw_uid;        /* user ID */gid_t   pw_gid;        /* group ID */char   *pw_gecos;      /* user information */char   *pw_dir;        /* home directory */char   *pw_shell;      /* shell program */
};

        通过用户名获取用户信息

struct passwd *getpwuid(uid_t uid);

        通过用户uid获取用户信息

etc/group

        是 Linux 和类 Unix 系统中的另一个重要文件,它用于存储用户组的信息。每个条目代表一个用户组,并且每行的字段通常由冒号(:)分隔。标准的字段包括:

        -组名:用户组的名称,通常不包含空格。
        -密码:用户组的加密密码,或者是一个“x”字符,表示密码存储在 /etc/gshadow 文件中。
        -组ID(GID):用户组的唯一标识符,是一个数字。
        -用户列表:属于该组的用户列表,可以是用户名或用户名的逗号分隔列表。

格式示例如下
         groupname:password:GID:user1,user2,user3

具体解释如下
    groupname:用户组的名称。
    password:用户组的加密密码,或者是一个“x”字符表示密码存储在 /etc/gshadow 文件中。
    GID:用户组的唯一标识符。
    user1,user2,user3:属于该组的用户列表,用户之间用逗号分隔。

struct group *getgrnam(const char *name);struct group {char   *gr_name;        /* group name */char   *gr_passwd;      /* group password */gid_t   gr_gid;         /* group ID */char  **gr_mem;         /* NULL-terminated array of pointersto names of group members */
};

        通过组名获取组信息

struct group *getgrgid(gid_t gid);

        通过组gid获取组信息

/etc/shadow

        文件在类 Unix 系统中用于存储用户账户的密码信息,以增强安全性。该文件通常只能由 root 用户访问,并且包含加密后的密码数据。每行对应一个用户,字段之间用冒号(:)分隔。标准的字段包括:

        -用户名:与 /etc/passwd 文件中的用户名相同。
        -加密密码:用户的加密密码或一个特定的值,如 * 或 !,表示账户被锁定或密码无效。
        -最后一次更改密码的日期:以从1970年1月1日(epoch)开始的天数计算。
        -密码最小更改间隔:用户必须等待的最小天数,才能再次更改密码。
        -密码最大有效期限:密码的最大有效天数。
        -密码警告期:在密码过期前,系统会警告用户的天数。
        密码到期后账户被禁用的天数:密码过期后,用户账户被禁用的天数。
        -预留字段:通常为空。

格式示例如下:
        username:$6$somehash$somehash:17000:0:99999:7:7:::

具体解释如下:
    username:用户的登录名。
    $6$somehash$somehash:加密的密码,其中 $6$ 表示使用的是 SHA-512 加密算法。
    17000:最后一次更改密码的日期(天数)。
    0:密码最小更改间隔。
    99999:密码最大有效期限。
    7:密码警告期。
    7:密码到期后账户被禁用的天数。
    :::预留字段,通常为空。


GLOB函数

int glob(const char *pattern, int flags,int (*errfunc) (const char *epath, int eerrno),glob_t *pglob);typedef struct {size_t gl_pathc;    /* 到目前为止匹配的路径数量 */char **gl_pathv;    /* 匹配的路径名列表 */size_t gl_offs;     /* 在 gl_pathv 中预留的槽位数 */
} glob_t;

参数说明:
--pattern:一个指向以null结尾的字符串的指针,指定了要匹配的文件名模式(文件路径)。模式可以包含如下特殊字符:
    *:匹配任意数量的字符。
    ?:匹配任意单个字符。
    [...]:匹配括号内的任意一个字符。

--flags:用于控制glob函数行为的标志位,可以是以下值的组合:
    GLOB_APPEND:如果pglob已经包含一些路径,新的路径将被追加到现有列表中,没有APPEND则是覆盖。
    GLOB_DOOFFS:减少分配给pglob->gl_pathv数组的内存量,数组大小为pglob->gl_pathc + 1。
    GLOB_ERR:如果发生错误并且提供了错误函数,函数将立即调用错误处理函数。
    GLOB_MARK:在每个匹配的路径名末尾添加一个斜杠(/)。
    GLOB_NOCHECK:如果模式没有匹配任何文件,返回空列表而不是GLOB_NOMATCH错误。
    GLOB_NOSORT:不按字母顺序对匹配的路径进行排序。

--errfunc:当出现错误并且GLOB_ERR标志被设置时,将调用此错误处理函数。该函数接受两个参数:错误路径和错误号。不需要错误检查时可以设置NULL。

--pglob:指向glob_t结构的指针,该结构用于存储匹配的路径列表和相关信息。


返回值
    成功时,返回 0。
    当没有找到匹配的文件名时,如果设置了GLOB_NOCHECK标志,返回 0,否则返回 GLOB_NOMATCH。
    发生错误时,返回非零错误代码。

void globfree(glob_t *pglob);

        销毁pglob申请空间,主要是char **gl_pathv;字符数组申请的空间 


利用glob实现du功能

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <glob.h>
#include <string.h>#define PATHSIZE 128static path_noloop(const char *path) {char *pos;pos = strrchr(path, '/')'if(pos == NULL)exit(1);if(strcmp(pos+1, ".") == 0 || strcmp(pos+1, "..") == 0)return 0;return 1;
}static int64_t K_du(const char* path){struct stat statres;//非目录if(lstat(path, &statres) < 0 ){perror("lstat()");exit(1);}if(!S_ISDIR(statres.st_mode))return statres.st_blocks/2;//目录char *nextpath[PATHSIZE];glob_t globres;int sum = statres.st_blocks;strncpy(nextpath, path, PATHSIZE);strncat(nextpath, "/*", PATHSIZE);glob(nextpath, 0, NULL, &globres);strncpy(nextpath, path, PATHSIZE);strncat(nextpath, "/.*", PATHSIZE);glob(nextpath, GLOB_APPEND, NULL, &globres);for(int i = 0; i < globres.gl_pathc; i++){if(path_noloop(globres.gl_pathv[i]))sum += mydu(globres.gl_pathv[i]);}return sum;
}

利用glob实现shell的ls功能

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <glob.h>
#include <sys/wait.h>// 定义命令分隔符
#define DELIMS " \t\n"// 定义一个结构体,用于存储 glob 函数的返回结果
struct cmd_st {glob_t globres;
};// promopt 函数用于显示提示符
static void promopt(void) {printf("[myshell-knoci-1.2] $ ");
}// parse 函数用于解析用户输入的命令行
static void parse(char *line, struct cmd_st *cmd) {char *token;  // 用于存储分割出的每个单词int i = 0;    // 用于控制是否追加到 glob 结构// 使用 strsep 函数分割字符串,直到没有更多单词while(1) {token = strsep(&line, DELIMS);if (token == NULL)break;if(token[0] == '\0')  // 跳过空字符串continue;// 对每个分割出的单词进行 glob 匹配,第一个单词不追加,后续追加glob(token, GLOB_NOCHECK | (i ? GLOB_APPEND : 0), NULL, &cmd->globres);i = 1;}
}// 主函数
int main(int argc, char *argv[]) {char *linebuf = NULL;  // 用于存储 getline 读取的整行命令size_t linebuf_size = 0; // linebuf 的当前分配大小struct cmd_st cmd;      // 定义 cmd 结构用于存储 glob 结果// 初始化 glob 结构的指针和计数器cmd.globres.gl_pathv = NULL;cmd.globres.gl_pathc = 0;pid_t pid;  // 存储 fork 函数返回的子进程 ID// 无限循环,持续读取和执行用户命令while(1) {promopt();  // 显示提示符// 使用 getline 函数从标准输入读取一行if(getline(&linebuf, &linebuf_size, stdin) < 0)break;// 解析命令行parse(linebuf, &cmd);// 假设没有内部命令,所有命令都是外部命令pid = fork();  // 创建子进程if(pid < 0) {perror("fork");  // 显示 fork 出错信息exit(1);}// 在子进程中执行命令if(pid == 0) {// 子进程中调用 execvp 执行命令if(cmd.globres.gl_pathc > 0) {execvp(cmd.globres.gl_pathv[0], cmd.globres.gl_pathv);}perror("execvp");  // 如果 execvp 失败,显示错误信息exit(1);  // 退出子进程} else {// 父进程等待子进程结束int status;waitpid(pid, &status, 0);}}// 清理资源globfree(&cmd.globres);  // 释放 glob 分配的内存free(linebuf);  // 释放 getline 分配的内存exit(0);  // 正常退出程序
}

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

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

相关文章

MySQL补充性文件

数据库专属单词 authentication #身份验证 delimiter #分隔符 character #字符集 collate #整理。 指定字符集的排序规则 unicode #统一码 flush #刷新 privileges #特权 string #串 set #设置 use #使用 zerofill #修饰符。0可以填补输出的值 unsigned #修饰符。无符…

德国云手机:企业移动办公解决方案

在现代商业环境中&#xff0c;移动办公已经成为一种趋势。德国云手机作为一种高效的解决方案&#xff0c;为企业提供了强大的支持。本文将探讨德国云手机如何优化企业的移动办公环境。 一、德国云手机的主要优势 高灵活性 德国云手机具有高度的灵活性&#xff0c;能够根据用户需…

Elasticsearch:Golang ECS 日志记录 - Logrus

ECS 记录器是你最喜欢的日志库的格式化程序/编码器插件。它们可让你轻松地将日志格式化为与 ECS 兼容的 JSON。 编码器以 JSON 格式记录&#xff0c;内部依赖于默认的 logrus.JSONFormatter。它还处理 ECS 错误格式的错误字段记录。 默认情况下&#xff0c;会添加以下字段&am…

【学习笔记】无人机系统(UAS)的连接、识别和跟踪(三)-架构模型和概念

引言 3GPP TS 23.256 技术规范&#xff0c;主要定义了3GPP系统对无人机&#xff08;UAV&#xff09;的连接性、身份识别、跟踪及A2X&#xff08;Aircraft-to-Everything&#xff09;服务的支持。 3GPP TS 23.256 技术规范&#xff1a; 【免费】3GPPTS23.256技术报告-无人机系…

js-toLocaleString()方法的使用(根据本地规则将对象转换为字符串-千分位或百分比等)

1.应用场景 toLocaleString() 方法是 JavaScript 中的一个内置方法&#xff0c;它可以根据本地规则将对象转换为字符串。但主要被用于 Date、Number 和 Array 对象上。 2.具体应用 2.1 date对象中使用 Date 对象上调用 toLocaleString() 方法时&#xff0c;它会根据运行代码的…

基于 Electron+Vite+Vue3+Sass 框架搭建

技术参考 技术描述Electron一个使用 JavaScript、HTML 和 CSS 构建桌面应用程序的框架。嵌入 Chromium 和 Node.jsElectron Forge用于打包和分发 Electron 应用程序的一体化工具。英文地址在此Vite前端构建工具Vue3用于构建用户界面的 JavaScript 框架vitejs/plugin-vueVite 插…

PlantUML 语法、图标和示例

基本语法 关键字 声明参与者的几个关键字 actor、boundary、control、entity、database、collections、participant 箭头样式 我们可以通过&#xff0c;修改箭头样式&#xff0c;来表达不一样的意思&#xff1a; 表示一条丢失的消息&#xff1a;末尾加 x让箭头只有上半部…

Redis在SpringBoot中遇到的问题:预热,雪崩,击穿,穿透

缓存预热 预热即在产品上线前&#xff0c;先对产品进行访问或者对产品的Redis中存储数据。 原因&#xff1a; 1. 请求数量较高 2. 主从之间数据吞吐量较大&#xff0c;数据同步操作频度较高,因为刚刚启动时&#xff0c;缓存中没有任何数据 解决方法&#xff1a; 1. 使用脚…

Kafka - 生产者

生产者消息对象 public class ProducerRecord<K, V> {private final String topic; // 主题private final Integer partition; //分区号private final Headers headers; //消息头部private final K key; //键private final V value; //值private final Long timestamp; …

opencv 按键开启连续截图,并加载提示图片

背景图小图 键盘监听使用的是pynput 库 保存图片时使用了年月日时分秒命名 原图&#xff1a; from pynput import keyboard import cv2 import time# 键盘监听 def on_press(key):global jieglobal guanif key.char a:jie Trueelif key.char d:jie Falseelif key.char…

配置三个Spring Boot应用并通过Nginx进行反向代理 讨论中

要配置三个Spring Boot应用并通过Nginx进行反向代理&#xff0c;你可以按照以下步骤操作&#xff1a; 步骤 1: 准备Spring Boot应用 确保每个Spring Boot应用都有不同的端口号。例如&#xff0c;你可以设置第一个应用监听8080端口&#xff0c;第二个监听8081端口&#xff0c;…

FPGA JTAG最小系统 EP2C5T144C8N

FPGA的文档没有相应的基础还真不容易看懂&#xff0c;下面是B站上对FPGA文档的解读(本文非对文档解读&#xff0c;只是为个人记录第三期&#xff1a;CycloneIV E最小系统板设计&#xff08;一&#xff09;从Datasheet上获取FPGA的基本参数_哔哩哔哩_bilibili 电源部份 核心电…

TS config

moduleResolution 是 TypeScript 编译器中的一个选项&#xff0c;用于控制如何解析模块导入。这个选项影响着 TypeScript 如何查找和解析 import 和 export 声明中指定的模块。 {"compilerOptions": {"moduleResolution": "Node"//小写也没问题…

SELinux的 getenforce setenforce 配置文件/etc/selinux/config的 SELINUX和SELINUXTYPE

SELinux&#xff08;Security-Enhanced Linux&#xff09;是一个为Linux系统提供访问控制安全策略的安全模块。它是Linux内核的一个功能强大的安全子系统&#xff0c;旨在提供访问控制安全策略机制&#xff0c;以限制程序中特定代码段的权限。SELinux超越了传统的UNIX权限模型&…

AI学习记录 -使用react开发一个网页,对接chatgpt接口,附带一些英语的学习prompt

实现了如下功能&#xff08;使用react实现&#xff0c;原创&#xff09; 实现功能&#xff1a; 1、对接gpt35模型问答&#xff0c;并实现了流式传输&#xff08;在java端&#xff09; 2、在实际使用中&#xff0c;我们的问答历史会经常分享给他人&#xff0c;所以下图的 copy …

Python酷库之旅-第三方库Pandas(042)

目录 一、用法精讲 141、pandas.Series.agg(regate)方法 141-1、语法 141-2、参数 141-3、功能 141-4、返回值 141-5、说明 141-6、用法 141-6-1、数据准备 141-6-2、代码示例 141-6-3、结果输出 142、pandas.Series.transform方法 142-1、语法 142-2、参数 142…

1196. 拐角I

问题描述 输入整数 &#x1d441;N &#xff0c;输出相应方阵。 输入一个整数 &#x1d441;N 。&#xff08; 0<&#x1d441;≤100) 输出一个方阵&#xff0c;每个数字的场宽为 3 附代码&#xff1a; #include<iostream> using namespace std; int main() { …

大屏数据看板一般是用什么技术实现的?

我们看到过很多企业都会使用数据看板&#xff0c;那么大屏看板的真正意义是什么呢&#xff1f;难道只是为了好看&#xff1f;答案当然不仅仅是。 大屏看板不仅可以提升公司形象&#xff0c;还可以提升企业的管理层次。对于客户&#xff0c;体现公司实力和品牌形象&#xff0c;…

域名解析到ipv6,并用CF隐藏端口

要求&#xff1a;域名解析到 IPv6 地址并隐藏端口 ‍ 效果&#xff1a;用域名 https://myhalo.soulio.top​ 访问http://[2409:8a62:867:4f12:56c7:5508:f7x6:8]:8080​。唯一缺点是延迟有点高。 ​​ ‍ 难度&#xff1a;需要有一定域名解析、cloudflare使用基础 ‍ 实…

org.springframework.context.annotation.DeferredImportSelector如何使用?

DeferredImportSelector 是 Spring 框架中一个比较高级的功能&#xff0c;主要用于在 Spring 应用上下文的配置阶段延迟导入某些组件或配置。这个功能特别有用&#xff0c;比如在处理依赖于其他自动配置的场景&#xff0c;或者当你想基于某些条件来决定是否导入特定的配置类时。…