深入理解Linux文件I/O:系统调用与标志位应用

目录

一、引入

二、标志位

1、什么是标志位?

2、标志位传递示例 

输出结果分析

关键点解释

三、文件描述符(File Descriptor)(先大概了解)

四、接口介绍:open()函数

1、命令查看

2、头文件

3、函数原型

4、参数说明

1. open的第一个参数pathname

2. open的第二个参数

1. 必需标志(必须指定且只能指定一个)

2. 可选标志(可组合使用)

补充说明

扩展:

3. open的第三个参数

基本权限位

特殊权限位

如何使用 mode_t?

1. 直接使用八进制数

2. 使用宏定义组合

3. 设置特殊权限

mode_t 的实际影响

5、返回值

五、接口介绍:close()函数

1、函数原型

2、参数说明

3、返回值

4、常见错误码(errno)

5、基本用法

6、深入理解close操作(了解)

7、注意事项(了解)

六、接口介绍:write()函数

1. write函数原型

2. 参数说明

3. 返回值

4、对文件进行写入操作示例

5. write函数的特点和注意事项

1. 部分写入

2. 阻塞与非阻塞

3. 原子性

4. 文件位置指针

七、接口介绍:read()函数

1、函数原型

2、参数说明

3、返回值

4、对文件进行读取操作示例

八、系统调用和库函数


一、引入

        操作系统提供多种文件访问方式,包括C语言接口、C++接口以及其他语言接口,同时也具备底层系统调用接口,系统调用才是文件操作最底层的实现方式。相较于高级语言库函数,系统调用更接近底层硬件。实际上,各种语言的库函数都是对系统接口的封装实现。

        无论是在Linux还是Windows平台运行C代码,C库函数都通过封装各自操作系统的系统调用接口来实现跨平台性。这种设计不仅保证了语言的通用性,也为二次开发提供了便利。

在学习系统文件I/O前,需要先掌握标志位的传递方法,这在系统文件I/O接口中会频繁使用:


二、标志位

1、什么是标志位?

        标志位(flag)是一种编程中常用的技术,它使用二进制位来表示不同的状态或选项。每个标志位通常对应一个特定的含义,通过位运算可以单独设置、清除或检查这些标志位。

标志位的优点包括:

  • 节省内存(多个布尔状态可以用一个整数的不同位表示)

  • 可以方便地组合多个状态(通过位或运算)

  • 可以高效地检查特定状态(通过位与运算)

2、标志位传递示例 

#include <stdio.h>// 定义三个标志位,每个标志位对应一个不同的二进制位
#define ONE   0x01    // 0000 0001 (二进制)
#define TWO   0x02    // 0000 0010
#define THREE 0x04    // 0000 0100void func(int flags) {// 检查flags是否包含ONE标志if (flags & ONE) printf("flags has ONE!\n");// 检查flags是否包含TWO标志if (flags & TWO) printf("flags has TWO!\n");// 检查flags是否包含THREE标志if (flags & THREE) printf("flags has THREE!\n");printf("\n");
}int main() {func(ONE);                  // 只传递ONE标志func(THREE);                // 只传递THREE标志func(ONE | TWO);            // 传递ONE和TWO标志的组合func(ONE | THREE | TWO);    // 传递所有三个标志的组合return 0;
}

输出结果分析

  1. func(ONE); 输出:flags has ONE!(只有ONE标志被设置)

  2. func(THREE); 输出:flags has THREE!(只有THREE标志被设置)

  3. func(ONE | TWO); 输出:

    flags has ONE!
    flags has TWO!(ONE和TWO标志被设置)
  4. func(ONE | THREE | TWO); 输出:

    flags has ONE!
    flags has TWO!
    flags has THREE!(所有三个标志都被设置)

关键点解释

  1. flags & ONE:这是一个位与运算,用于检查flags变量中是否设置了ONE标志位。如果结果为非零,则表示设置了该标志。

  2. ONE | TWO:这是一个位或运算,用于组合多个标志位。结果是一个同时包含ONE和TWO标志的值。

  3. 标志位的值选择:每个标志位对应一个不同的二进制位(0x01, 0x02, 0x04等),这样它们可以独立设置和检查而不会相互干扰。

这种标志位技术在系统编程、硬件接口和需要高效表示多个选项的场景中非常常见。


三、文件描述符(File Descriptor)(先大概了解)

        在Unix/Linux系统中,所有I/O操作都是通过文件描述符完成的。文件描述符是一个非负整数,用于标识打开的文件。系统为每个进程维护一个文件描述符表。

三个标准的文件描述符:

  • 0: 标准输入(stdin)

  • 1: 标准输出(stdout)

  • 2: 标准错误(stderr)


四、接口介绍:open()函数

    open()函数是Linux/Unix系统中用于打开或创建文件的核心系统调用之一,它是文件操作的基础。

1、命令查看

man 2 open

2、头文件

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

3、函数原型

系统接口中使用open函数打开文件,open函数的函数原型如下:

int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);

4、参数说明

1. open的第一个参数pathname

        open函数的第一个参数是pathname,表示要打开或创建的文件路径名,可以是相对路径或绝对路径。

  • 若pathname以路径的方式给出,则当需要创建该文件时,就在pathname路径下进行创建。
  • 若pathname以文件名的方式给出,则当需要创建该文件时,默认在当前路径下进行创建。(注意当前路径的含义)

2. open的第二个参数

        open函数的第二个参数是flags(文件打开方式标志位),表示打开文件的标志,控制文件的打开方式和行为。flags参数由以下一个或多个值通过位或(|)操作组合而成。

        例如,若想以只写的方式打开文件,但当目标文件不存在时自动创建文件,则第二个参数设置如下:

O_WRONLY | O_CREAT
1. 必需标志(必须指定且只能指定一个)
标志说明
O_RDONLY只读方式打开文件
O_WRONLY只写方式打开文件
O_RDWR读写方式打开文件
2. 可选标志(可组合使用)
标志说明
O_CREAT如果文件不存在,则创建它(需配合 mode 参数设置权限)
O_EXCL与 O_CREAT 一起使用,确保文件不存在时才创建(用于原子性创建文件)
O_TRUNC如果文件已存在且是普通文件,则截断为0字节(清空文件)
O_APPEND追加模式,每次写入都会自动追加到文件末尾(避免并发写入冲突)
O_NONBLOCK / O_NDELAY非阻塞模式打开文件(适用于 FIFO、管道、设备文件等)
O_SYNC同步 I/O,每次写操作都会等待数据真正写入物理存储(性能较低,但数据更安全)
O_NOFOLLOW如果路径是符号链接,则不跟随(防止符号链接攻击)
O_DIRECTORY如果路径不是目录,则打开失败(确保只打开目录)
O_CLOEXEC设置 close-on-exec 标志,exec 时自动关闭文件描述符(防止子进程继承)

补充说明

  • 必需标志O_RDONLY / O_WRONLY / O_RDWR)必须选且仅选一个

  • 可选标志可以通过 |(按位或)组合使用,例如:

    int fd = open("file.txt", O_WRONLY | O_CREAT | O_TRUNC, 0644);
  • O_EXCL 必须与 O_CREAT 一起使用,否则无意义。

  • O_TRUNC 仅对普通文件有效,对目录、设备文件等无效。

  • O_APPEND 在多进程/多线程写入时能避免竞争条件(Race Condition)。

  • O_SYNC 会影响性能,但能确保数据持久化(适用于关键数据存储)。

扩展:

        系统接口open的第二个参数flags是整型,有32比特位,若将一个比特位作为一个标志位,则理论上flags可以传递32种不同的标志位。

实际上传入flags的每一个选项在系统当中都是以宏的方式进行定义的:

例如,O_RDONLY、O_WRONLY、O_RDWR和O_CREAT在系统当中的宏定义如下:

#define O_RDONLY         00
#define O_WRONLY         01
#define O_RDWR           02
#define O_CREAT        0100

        这些宏定义选项的二进制编码具有一个共同特征:每个选项的二进制序列中仅有一位为1(O_RDONLY选项除外,其二进制值为全0,表示默认选项)。不同选项的置1位各不相同,这使得open函数内部可以通过简单的"与"运算来检测特定选项是否被设置。

int open(arg1, arg2, arg3)
{if (arg2&O_RDONLY)//检查是否设置了O_RDONLY选项{}if (arg2&O_WRONLY)//检查是否设置了O_WRONLY选项{}if (arg2&O_RDWR)//检查是否设置了O_RDWR选项{}if (arg2&O_CREAT)//检查是否设置了O_CREAT选项{}//...
}

3. open的第三个参数

        在 Unix/Linux 系统调用中,mode_t 是一个数据类型,用于表示文件的权限模式(permission mode)。它通常是一个无符号整数类型(如 unsigned int),用于指定文件的访问权限。

        当使用O_CREAT创建新文件时,必须指定mode参数,表示新文件的权限。mode通常用八进制表示,如0644。

例如,设置mode=0666会赋予文件-rw-rw-rw-的权限。

        需要注意的是,实际文件权限会受到umask(文件创建掩码)的影响。计算公式为:实际权限 = mode & (~umask)。在默认umask=0002的情况下,当mode=0666时,实际创建的权限为0664(即-rw-rw-r--)。

若要完全按照mode参数设置权限,可以在创建文件前调用umask(0)将掩码清零。

umask(0); //将文件默认掩码设置为0

注意: 当不需要创建文件时,open的第三个参数可以不必设置。 

    open() 函数在创建文件(使用 O_CREAT 标志)时,需要指定文件的权限模式 mode_t。这个参数决定了文件的读、写、执行权限,以及特殊权限位(如 setuid、setgid 等)。

基本权限位

mode_t 由多个权限位组合而成,可以使用八进制数或宏定义来设置:

宏定义八进制值权限说明
S_IRUSR0400用户(owner)可读
S_IWUSR0200用户可写
S_IXUSR0100用户可执行
S_IRGRP0040组(group)可读
S_IWGRP0020组可写
S_IXGRP0010组可执行
S_IROTH0004其他用户(others)可读
S_IWOTH0002其他用户可写
S_IXOTH0001其他用户可执行
特殊权限位
宏定义八进制值权限说明
S_ISUID04000设置用户ID(setuid)
S_ISGID02000设置组ID(setgid)
S_ISVTX01000粘滞位(sticky bit)
如何使用 mode_t
1. 直接使用八进制数

最常见的用法是直接使用 3位八进制数 来设置权限:

int fd = open("example.txt", O_CREAT | O_WRONLY, 0644);
  • 0644 表示:

    • 用户(owner)64+2,即 rw-

    • 组(group)4r--

    • 其他用户(others)4r--

2. 使用宏定义组合

也可以使用宏定义组合:

int fd = open("example.txt", O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
  • 等同于 0644rw-r--r--

3. 设置特殊权限

例如,设置 setuid 权限(仅对可执行文件有效):

int fd = open("program", O_CREAT | O_WRONLY, S_IRWXU | S_ISUID);
  • S_IRWXU = 0700rwx------

  • S_ISUID = 04000(设置 setuid 位)

  • 最终权限:4700rws------

mode_t 的实际影响
  • open() 的 mode 参数仅在 O_CREAT 时生效(如果文件已存在,则不会修改权限)。

  • 最终权限会受到 umask 的影响:

    mode_t final_mode = mode & ~umask;

    例如,如果 umask=002,而 mode=0666,则实际权限是 0664rw-rw-r--)。

5、返回值

open函数的返回值是新打开文件的文件描述符。

  • 成功:成功时返回一个非负整数文件描述符。
  • 失败:失败时返回-1并设置errno。

我们可以尝试一次打开多个文件,然后分别打印它们的文件描述符: 

#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
int main()
{umask(0);int fd1 = open("log1.txt", O_RDONLY | O_CREAT, 0666);int fd2 = open("log2.txt", O_RDONLY | O_CREAT, 0666);int fd3 = open("log3.txt", O_RDONLY | O_CREAT, 0666);int fd4 = open("log4.txt", O_RDONLY | O_CREAT, 0666);int fd5 = open("log5.txt", O_RDONLY | O_CREAT, 0666);printf("fd1:%d\n", fd1);printf("fd2:%d\n", fd2);printf("fd3:%d\n", fd3);printf("fd4:%d\n", fd4);printf("fd5:%d\n", fd5);return 0;
}

运行程序后可以看到,打开文件的文件描述符是从3开始连续且递增的:

我们再尝试打开一个根本不存在的文件,也就是open函数打开文件失败: 

#include <stdio.h>                                                                                       
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{int fd = open("test.txt", O_RDONLY);printf("%d\n", fd);return 0;
}

运行程序后可以看到,打开文件失败时获取到的文件描述符是-1: 

        文件描述符本质上是一个指针数组的索引,该数组中的每个指针都指向一个已打开文件的文件信息。通过文件描述符即可访问对应的文件信息。

        当open函数成功打开文件时,系统会扩展指针数组并返回新增指针的索引值;若打开失败则直接返回-1。因此,连续成功打开多个文件时,获得的文件描述符是依次递增的。

        Linux进程默认打开三个标准文件描述符:0(标准输入)、1(标准输出)和2(标准错误)。这就是新打开文件时,文件描述符从3开始分配的原因。

open 函数的具体使用方式取决于应用场景:

  • 若目标文件不存在,需要创建新文件,则使用带三个参数的 open(第三个参数表示创建文件的默认权限)
  • 若文件已存在,则使用带两个参数的 open

五、接口介绍:close()函数

close()函数是Linux/Unix系统中用于关闭已打开文件描述符的重要系统调用。

1、函数原型

#include <unistd.h>int close(int fd);

2、参数说明

fd(文件描述符)

        要关闭的文件描述符(file descriptor),这是之前通过open()creat()pipe()dup()等函数获得的文件描述符。

3、返回值

  • 成功时返回0

  • 失败时返回-1,并设置errno来指示错误原因

4、常见错误码(errno)

  • EBADF:fd不是有效的已打开文件描述符

  • EINTR:close操作被信号中断

  • EIO:发生了I/O错误

5、基本用法

#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>int main() {int fd = open("example.txt", O_RDONLY);if (fd == -1) {perror("open failed");return 1;}// 使用文件描述符进行读写操作...if (close(fd) == -1) {perror("close failed");return 1;}return 0;
}

6、深入理解close操作(了解)

  1. 资源释放

    • 关闭文件描述符会释放内核为该文件分配的所有资源

    • 释放文件描述符本身,使其可被后续的open()pipe()等调用重用

  2. 缓冲区刷新

    • 对于输出文件,close操作会确保所有缓冲数据被写入磁盘

    • 对于使用mmap()映射的文件,close操作不会解除映射,但关闭后访问映射内存可能导致SIGBUS信号

  3. 文件锁释放

    • 进程终止时所有文件描述符会自动关闭

    • 关闭文件描述符会释放该进程在该文件上设置的所有锁(使用fcntl()设置的锁)

7、注意事项(了解)

  1. 多次关闭

    • 重复关闭同一个文件描述符是错误行为

    • 在多线程环境中尤其需要注意,可能引发竞态条件

  2. 信号中断处理

    • 如果close()被信号中断,某些系统上需要重新调用close()

    • 更安全的做法是使用以下模式:

      while (close(fd) == -1) {if (errno != EINTR) {perror("close error");break;}// 如果是被信号中断,则继续尝试关闭
      }
  3. 文件描述符泄漏

    • 忘记关闭文件描述符是常见编程错误

    • 长期运行的进程可能导致文件描述符耗尽

    • 建议在打开文件后立即考虑关闭操作,使用goto或RAII模式管理资源。


六、接口介绍:write()函数

    write() 是Linux/Unix系统中一个非常重要的低级文件I/O函数,用于将数据写入文件描述符对应的文件或设备。

1. write函数原型

#include <unistd.h>ssize_t write(int fd, const void *buf, size_t count);

2. 参数说明

  • fd:文件描述符,通常由open()函数返回

  • buf:指向要写入数据的缓冲区的指针

  • count:要写入的字节数

3. 返回值

  • 成功时:返回实际写入的字节数(可能小于请求的count

  • 失败时:返回-1,并设置errno

4、对文件进行写入操作示例

#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_WRONLY | O_CREAT, 0666);if (fd < 0){perror("open");return 1;}const char* msg = "hello syscall\n";for (int i = 0; i < 5; i++){write(fd, msg, strlen(msg));}close(fd);return 0;
}

运行程序后,在当前路径下就会生成对应文件,文件当中就是我们写入的内容:

5. write函数的特点和注意事项

1. 部分写入

write()可能会执行部分写入,即返回值小于请求的字节数。这种情况常见于:

  • 磁盘空间不足

  • 被信号中断

  • 非阻塞模式下资源暂时不可用

2. 阻塞与非阻塞

  • 常规文件通常不会阻塞

  • 管道、套接字等特殊文件可能阻塞

  • 可以设置O_NONBLOCK标志使操作非阻塞

3. 原子性

对于常规文件,小于PIPE_BUF大小的写入是原子的(通常为4096字节)

4. 文件位置指针

write()操作会更新文件的当前位置指针


七、接口介绍:read()函数

    read() 函数是Linux/Unix系统中用于从文件描述符读取数据的基本系统调用之一。它是文件I/O操作的核心函数之一,属于POSIX标准的一部分。

1、函数原型

#include <unistd.h>ssize_t read(int fd, void *buf, size_t count);

2、参数说明

  1. fd (file descriptor):文件描述符,是一个整数值,指向要读取的文件

    • 通常由open()函数返回

    • 标准输入的文件描述符是0

  2. buf:指向内存缓冲区的指针,用于存放读取到的数据。必须预先分配足够的内存空间

  3. count:请求读取的字节数。通常是缓冲区的大小

3、返回值

  • 成功时:返回实际读取的字节数

    • 可能小于请求的字节数(例如接近文件末尾时)

    • 返回0表示到达文件末尾(EOF)

  • 失败时:返回-1,并设置errno

    • 常见的errno值:

      • EAGAIN/EWOULDBLOCK:非阻塞I/O且无数据可读

      • EBADF:无效的文件描述符

      • EINTR:被信号中断

      • EIO:I/O错误

4、对文件进行读取操作示例

#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;}char ch;while (1){ssize_t s = read(fd, &ch, 1);if (s <= 0){break;}write(1, &ch, 1); //向文件描述符为1的文件写入数据,即向显示器写入数据}close(fd);return 0;
}

运行程序后,就会将我们刚才写入文件的内容读取出来,并打印在显示器上:


八、系统调用和库函数

        总的来说,我们更加能明白开始时提到的“实际上,各种语言的库函数都是对系统接口的封装实现。”这句话!!!

在了解返回值之前,需要明确两个重要概念:系统调用和库函数

  • fopen、fclose、fread、fwrite这些是C标准库提供的函数,称为库函数(libc)
  • 而open、close、read、write、lseek等则是操作系统直接提供的接口,称为系统调用
  • 这与我们之前讲解操作系统概念时展示的系统架构图是一致的

        系统调用接口与库函数的关系十分清晰。可以明确地说,f#系列函数是对系统调用的封装,为二次开发提供了便利。

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

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

相关文章

海康线扫相机通过采集卡的取图设置

目录 1、扫描高度小于65000行 1.1 软触发 1、采集卡设置项 2、相机设置项 1.2 硬触发 1、采集卡设置项 2、相机设置项 2、扫描高度大于65000行 1.1 软触发 1、采集卡设置项 2、相机设置 1.2 硬触发 1、采集卡设置项 2、相机设置 2.1 帧扫描 2.2 行扫描 3、注意…

InfluxDB 3与Apache Parquet:打造高性能时序数据存储与分析解决方案

在当今数据驱动的时代&#xff0c;各行业产生的数据量呈爆炸式增长&#xff0c;如何高效存储和管理海量数据成为企业和开发者面临的重大挑战。对于时序数据而言&#xff0c;其具有数据量大、写入频繁、查询模式多样等特点&#xff0c;对存储系统的性能和效率提出了更高的要求。…

20250718-4-Kubernetes 应用程序生命周期管理-Pod对象:实现机制_笔记

一、Pod对象&#xfeff;&#xfeff;1. 资源共享实现机制1&#xff09;共享网络&#xfeff;基本概念实现方式&#xff1a;通过将业务容器网络加入到负责网络的容器&#xff08;infra container&#xff09;实现网络共享核心特点&#xff1a;共享网络协议栈&#xff08;包括TC…

防爆手机是什么?能用普通手机改装吗?

在石油开采平台的井架之上&#xff0c;在化工车间的反应釜旁&#xff0c;在煤矿深达千米的巷道中&#xff0c;一群特殊的工作人员正使用着看似普通的通讯设备。这些设备外壳上醒目的Ex防爆认证标志&#xff0c;揭示着其与众不同的身份——防爆手机。这类专为易燃易爆环境设计的…

gem install报错解析

报错内容 [rootlocalhost ~]# gem install bundler Fetching: bundler-2.6.9.gem (100%) ERROR: Error installing bundler:bundler requires Ruby version > 3.1.0. The current ruby version is 2.5.0.解决方案&#xff08;任选其一&#xff09; 这个错误表明你当前的 Ru…

css 如何实现大屏4个占位 中屏2个 小屏幕1个

1、 使用grid.container {display: grid;grid-template-columns: repeat(4, 1fr);gap: 20px;border: 1px solid red;width: 400px;height: 400px;}media (max-width: 768px) {.container {grid-template-columns: 1fr;}}media (min-width: 768px) and (max-width: 992px) {.con…

Redis学习系列之—— JDHotKey 热点缓存探测系统

一、为什么需要热点缓存探测 在回答这个问题前&#xff0c;我们先考虑一下&#xff1a;为什么光用 Redis 还不够&#xff0c;还需要使用本地缓存&#xff1f; 一般来说&#xff0c;Redis 集群的性能能抗住几十万并发&#xff0c;能够应付大部分情况。但对于一些头部 APP&#x…

Linux 安全加固

Linux 安全加固需要从​​用户权限、系统服务、网络防护、日志审计、文件系统、访问控制​​等多个维度入手&#xff0c;目标是减少攻击面、限制未授权访问、提升系统健壮性。以下是​​详细步骤实操示例​​&#xff0c;覆盖主流 Linux 发行版&#xff08;如 CentOS/Ubuntu&am…

【Docker#2】容器历史发展 | 虚拟化实现方式

一、前言 – 容器技术发展史 容器技术是现今计算技术的重要组成部分&#xff0c;其发展历程可以追溯到很早的计算机系统提供的进程隔离工具。以下是容器技术的发展历程&#xff0c;其中涵盖了从早期的进程隔离技术到现代云计算和云原生的演变&#xff1a; ① Jail 时代 1979 年…

React + Mermaid 图表渲染消失问题剖析及 4 种代码级修复方案

Mermaid 是一个流行的库&#xff0c;它可以将文本图表&#xff08;例如 graph LR; A-->B;&#xff09;转换为 SVG 图表。在静态 HTML 页面中&#xff0c;Mermaid 会查找 <pre class"mermaid"> 代码块&#xff0c;并在页面加载时将它们替换为渲染后的图表。它…

[Element]修改el-pagination背景色

[Element]修改el-pagination背景色 代码 <el-pagination:current-page.sync"queryParams.current":page-size.sync"queryParams.size":page-sizes"[10, 20, 50, 100]"layout"prev, pager, next, jumper, sizes":total"queryP…

Docker 可用镜像列表

Docker 镜像源列表&#xff08;7月15日更新-长期&免费&#xff09;_dockerhub国内镜像源列表-CSDN博客

低代码可视化工作流的系统设计与实现路径研究

一、背景分析在数字化转型不断深化的背景下&#xff0c;企业业务流程呈现出高度定制化与动态调整的趋势&#xff0c;传统信息系统在开发周期、实施成本与扩展能力上的局限性日益凸显&#xff0c;已难以支撑快速响应和敏捷迭代的实际需求。面向这一现实挑战&#xff0c;基于 BPM…

mac mlx大模型框架的安装和使用

mlx是apple平台的大模型推理框架&#xff0c;对mac m1系列处理器支持较好。 这里记录mlx安装和运行示例。 1 安装mlx框架 conda create -n mlx python3.12 conda activate mlx pip install mlx-lm 2 运行mlx测试例 以下是测试程序&#xff0c;使用方法和hf、vllm等推理框架基…

JAVA 使用Apache POI合并Word文档并保留批注的实现

一、需求背景 在实际工作中&#xff0c;我们经常需要将多个Word文档合并成一个文件。但当文档中包含批注&#xff08;Comments&#xff09;时&#xff0c;传统的复制粘贴会导致批注丢失或引用错乱。本文将介绍如何通过Java和Apache POI库实现保留批注及引用关系的文档合并功能。…

Linux的服务管理工具:`systemd`(`systemctl`)和`SysVinit ` 笔记250718

Linux的服务管理工具:systemd(systemctl)和SysVinit 笔记250718 Linux的服务管理工具 Linux 的服务管理工具随着发行版和初始化系统的发展而演变。以下是主要的服务管理工具及其对应的初始化系统&#xff1a; 1. systemd (现代主流标准) 初始化系统&#xff1a; 是绝大多数…

Couchbase 可观测性最佳实践

Couchbase 介绍 Couchbase 是一个开源的分布式 NoSQL 数据库&#xff0c;专为高性能和高可扩展性设计&#xff0c;适用于实时数据处理的企业应用。它结合键值存储和文档数据库的优势&#xff0c;支持 JSON 文档存储&#xff0c;并通过 N1QL&#xff08;类 SQL 查询语言&#x…

构建基于MCP的LLM聊天机器人客户端开发指南

引言 在当今人工智能技术快速发展的时代&#xff0c;大型语言模型(LLM)已成为构建智能应用的核心组件。MCP(Modular Conversational Platform)作为一个强大的对话平台&#xff0c;为开发者提供了将LLM能力与自定义工具集成的标准化方式。本文将详细介绍如何使用Python开发一个…

接口测试的原则、用例与流程详解

&#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 一、接口的介绍软件测试中&#xff0c;常说的接口有两种&#xff1a;图形用户接口&#xff08;GUI&#xff0c;人与程序的接口&#xff09;、应用程序编程接口&am…

ubuntu 22.02 带外进单用户拯救系统

不停地按 F7 &#xff0c;然后进到 menu &#xff0c;选择 ubuntu &#xff0c;然后按下 ESC &#xff0c;然后瞬间会刷一个 ubuntu 的选项&#xff08;默认是在第一的位置&#xff0c;直接快速按下 e&#xff09;即可进入单用户模式。 找到类似 linux /boot/vmlinuz-xxx rootU…