当前位置: 首页 > news >正文

深入C语言文件操作:从库函数到系统调用

引言

文件操作是编程中不可或缺的一部分,尤其在C语言中,文件操作不仅是处理数据的基本手段,也是连接程序与外部世界的重要桥梁。C语言提供了丰富的库函数来处理文件,如 fopenfclosefreadfwrite 等。然而,这些库函数实际上是基于操作系统提供的系统调用构建的。理解库函数和系统调用之间的关系,不仅有助于编写高效的代码,还能帮助我们更好地理解底层操作系统的机制。

本文将深入探讨C语言文件操作中的库函数和系统调用,解释它们的工作原理、区别和联系,并通过实际示例展示如何使用这些函数。
在这里插入图片描述

C标准库函数与系统调用概述

6.1 C标准库函数

C标准库函数是ANSI C标准中定义的一组函数,它们提供了一种跨平台的方式来处理文件操作。这些函数通常在 stdio.h 头文件中声明,并且在大多数操作系统中都有实现。常见的文件操作库函数包括:

  • fopen:打开文件。
  • fclose:关闭文件。
  • fread:从文件中读取数据。
  • fwrite:向文件中写入数据。
  • fgetc:从文件中读取一个字符。
  • fputc:向文件中写入一个字符。
  • fgets:从文件中读取一行。
  • fputs:向文件中写入一行。
  • fseek:移动文件指针。
  • ftell:获取文件指针的当前位置。
  • rewind:将文件指针重置到文件开头。

6.2 系统调用

系统调用是操作系统提供给用户程序的一组接口,用于请求操作系统执行特定的低级操作。系统调用通常在内核态执行,提供了对硬件设备的直接访问。常见的文件操作系统调用包括:

  • open:打开文件。
  • close:关闭文件。
  • read:从文件中读取数据。
  • write:向文件中写入数据。
  • lseek:移动文件指针。
  • ioctl:控制设备。

库函数与系统调用的区别

6.3 工作空间不同

  • 库函数:运行在用户态,通常包含在标准库中,如 glibc
  • 系统调用:运行在内核态,由操作系统内核提供。

6.4 缓冲机制不同

  • 库函数:通常使用缓冲机制来提高性能。例如,freadfwrite 会先将数据读取到内存缓冲区,然后再批量处理。
  • 系统调用:不使用缓冲机制,每次调用都会直接与文件系统交互。

6.5 可移植性不同

  • 库函数:具有良好的可移植性,可以在不同的操作系统上使用相同的接口。
  • 系统调用:依赖于特定的操作系统,不同操作系统的系统调用接口可能不同。

6.6 性能差异

  • 库函数:由于使用了缓冲机制,减少了用户态和内核态之间的切换次数,通常性能更高。
  • 系统调用:每次调用都会导致用户态和内核态之间的切换,性能较低。

库函数与系统调用的联系

尽管库函数和系统调用在许多方面有所不同,但它们之间存在着密切的联系。实际上,许多库函数最终会调用系统调用来完成实际的文件操作。

6.7 fopenopen

fopen 函数用于打开文件,并返回一个指向 FILE 结构的指针。fopen 实际上调用了 open 系统调用。

示例代码:

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>int main() {// 使用 fopen 打开文件FILE *file = fopen("example.txt", "r");if (file == NULL) {fprintf(stderr, "打开文件失败: %s\n", strerror(errno));return 1;}// 使用 open 系统调用打开文件int fd = open("example.txt", O_RDONLY);if (fd == -1) {perror("打开文件失败");return 1;}fclose(file);close(fd);return 0;
}

6.8 freadread

fread 函数用于从文件中读取数据,并返回实际读取的数据项数。fread 实际上调用了 read 系统调用。

示例代码:

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>int main() {// 使用 fopen 打开文件FILE *file = fopen("example.txt", "r");if (file == NULL) {fprintf(stderr, "打开文件失败: %s\n", strerror(errno));return 1;}// 使用 open 系统调用打开文件int fd = open("example.txt", O_RDONLY);if (fd == -1) {perror("打开文件失败");return 1;}char buffer[100];size_t bytes_read;// 使用 fread 读取文件bytes_read = fread(buffer, 1, sizeof(buffer), file);if (ferror(file)) {fprintf(stderr, "读取文件失败: %s\n", strerror(errno));fclose(file);close(fd);return 1;}buffer[bytes_read] = '\0';printf("fread: %s\n", buffer);// 使用 read 系统调用读取文件bytes_read = read(fd, buffer, sizeof(buffer));if (bytes_read == -1) {perror("读取文件失败");close(fd);return 1;}buffer[bytes_read] = '\0';printf("read: %s\n", buffer);fclose(file);close(fd);return 0;
}

6.9 fwritewrite

fwrite 函数用于向文件中写入数据,并返回实际写入的数据项数。fwrite 实际上调用了 write 系统调用。

示例代码:

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>int main() {// 使用 fopen 打开文件FILE *file = fopen("example.txt", "w");if (file == NULL) {fprintf(stderr, "打开文件失败: %s\n", strerror(errno));return 1;}// 使用 open 系统调用打开文件int fd = open("example.txt", O_WRONLY | O_CREAT, 0644);if (fd == -1) {perror("打开文件失败");return 1;}char *message = "Hello, World!\n";// 使用 fwrite 写入文件if (fwrite(message, 1, strlen(message), file) != strlen(message)) {if (ferror(file)) {fprintf(stderr, "写入文件失败: %s\n", strerror(errno));fclose(file);close(fd);return 1;}}// 使用 write 系统调用写入文件if (write(fd, message, strlen(message)) == -1) {perror("写入文件失败");close(fd);return 1;}fclose(file);close(fd);return 0;
}

6.10 fcloseclose

fclose 函数用于关闭文件,并刷新缓冲区。fclose 实际上调用了 close 系统调用。

示例代码:

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>int main() {// 使用 fopen 打开文件FILE *file = fopen("example.txt", "w");if (file == NULL) {fprintf(stderr, "打开文件失败: %s\n", strerror(errno));return 1;}// 使用 open 系统调用打开文件int fd = open("example.txt", O_WRONLY | O_CREAT, 0644);if (fd == -1) {perror("打开文件失败");return 1;}char *message = "Hello, World!\n";// 使用 fwrite 写入文件if (fwrite(message, 1, strlen(message), file) != strlen(message)) {if (ferror(file)) {fprintf(stderr, "写入文件失败: %s\n", strerror(errno));fclose(file);close(fd);return 1;}}// 使用 write 系统调用写入文件if (write(fd, message, strlen(message)) == -1) {perror("写入文件失败");close(fd);return 1;}// 使用 fclose 关闭文件if (fclose(file) != 0) {fprintf(stderr, "关闭文件失败: %s\n", strerror(errno));close(fd);return 1;}// 使用 close 系统调用关闭文件if (close(fd) == -1) {perror("关闭文件失败");return 1;}return 0;
}

文件描述符与缓冲区

6.11 文件描述符

文件描述符(File Descriptor,FD)是一个用于引用打开文件和其他类型的I/O资源的整数。每个进程都有自己的文件描述符表,用于跟踪进程打开的所有文件和I/O资源。

  • 唯一标识:文件描述符为每个打开的文件或I/O资源提供了一个唯一的标识符,通常是一个非负整数。
  • 文件描述符表:每个进程都有自己的文件描述符表,这是一个内核数据结构,用于跟踪进程打开的所有文件和I/O资源。
  • 系统调用:文件描述符通常通过系统调用如 openreadwriteclose 等进行操作。open 调用返回一个新的文件描述符,readwrite 使用文件描述符来读取或写入数据,而 close 用于释放文件描述符。
  • 标准流:Linux为标准输入(stdin)、标准输出(stdout)和标准错误(stderr)分别分配了文件描述符0、1和2。
  • 缓冲机制:Linux内核可能会对通过文件描述符进行的I/O操作使用缓冲机制,以提高性能和减少实际的磁盘I/O操作。
  • 错误处理:当系统调用失败时,会返回-1,并且全局变量 errno 被设置为表示错误的特定值。
  • 多路复用:文件描述符可以用于I/O多路复用机制,如 selectpollepoll,允许进程同时监控多个文件描述符上的I/O状态。
  • 继承性:当创建新进程时,子进程会继承父进程的文件描述符表中的文件描述符,除非它们在子进程中被显式地关闭。
  • 重定向:文件描述符可以通过 dupdup2 等函数进行重定向,允许将一个文件描述符的引用复制到另一个文件描述符上。
  • 文件锁:文件描述符可以用于对文件加锁,以控制对文件的并发访问。

6.12 缓冲区机制

缓冲区机制是C标准库中用于提高I/O性能的一种技术。缓冲区可以减少用户态和内核态之间的切换次数,从而提高性能。

  • 全缓冲:对于文件,通常是全缓冲的。这意味着数据会先写入缓冲区,当缓冲区满或文件关闭时,数据才会被写入文件。
  • 行缓冲:对于终端输入输出,通常是行缓冲的。这意味着数据会在遇到换行符时被写入文件。
  • 无缓冲:对于标准错误输出,通常是无缓冲的。这意味着数据会立即被写入文件。

实际应用案例

6.13 文件拷贝示例

下面是一个使用库函数和系统调用实现文件拷贝的示例。该示例展示了如何结合使用库函数和系统调用来完成文件操作。

示例代码:

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>int copy_file(const char *src_path, const char *dst_path) {// 使用 fopen 打开源文件FILE *src_file = fopen(src_path, "rb");if (src_file == NULL) {fprintf(stderr, "打开源文件失败: %s\n", strerror(errno));return 1;}// 使用 open 系统调用打开目标文件int dst_fd = open(dst_path, O_WRONLY | O_CREAT | O_TRUNC, 0644);if (dst_fd == -1) {fprintf(stderr, "打开目标文件失败: %s\n", strerror(errno));fclose(src_file);return 1;}char buffer[1024];size_t bytes_read;while ((bytes_read = fread(buffer, 1, sizeof(buffer), src_file)) > 0) {if (ferror(src_file)) {fprintf(stderr, "读取源文件失败: %s\n", strerror(errno));fclose(src_file);close(dst_fd);return 1;}if (write(dst_fd, buffer, bytes_read) == -1) {perror("写入目标文件失败");fclose(src_file);close(dst_fd);return 1;}}if (ferror(src_file)) {fprintf(stderr, "读取源文件失败: %s\n", strerror(errno));fclose(src_file);close(dst_fd);return 1;}if (fclose(src_file) != 0) {fprintf(stderr, "关闭源文件失败: %s\n", strerror(errno));close(dst_fd);return 1;}if (close(dst_fd) == -1) {perror("关闭目标文件失败");return 1;}return 0;
}int main() {const char *src_path = "source.txt";const char *dst_path = "destination.txt";if (copy_file(src_path, dst_path) == 0) {printf("文件复制成功\n");} else {printf("文件复制失败\n");}return 0;
}

文件操作的底层原理

6.14 文件描述符与文件信息区

每个被使用的文件都在内存中开辟了一个相应的文件信息区,用来存放文件的相关信息(如文件的名字、文件状态及文件当前的位置等)。这些信息是保存在一个结构体变量中的。该结构体类型是由系统声明的,取名 FILE

每当打开一个文件的时候,系统会根据文件的情况自动创建一个 FILE 结构的变量,并填充其中的信息,使用者不必关心细节。一般都是通过一个 FILE 的指针来维护这个 FILE 结构的变量,这样使用起来更加方便。

6.15 文件指针的位置

文件指针可以指向文件的任意位置,通常用来记录下一次读取或写入的位置。可以通过一些函数来移动文件指针的位置,如 fseek 函数和 rewind 函数。可以通过一些函数来获取当前文件指针的位置,如 ftell 函数。

6.16 文件的打开和关闭

在使用文件之前应该打开文件,使用完之后应该关闭文件。ANSI C 规定使用 fopen 来打开文件,用 fclose 来关闭文件。

文件打开方式 mode 参数说明:

  • "r":只读模式,打开一个已经存在的文本文件,用于输入。
  • "w":只写模式,打开一个文本文件用于输出,如果文件已存在则清空原有内容,如果文件不存在则创建新文件。
  • "a":追加模式,打开一个文本文件用于在文件尾部追加数据,如果文件不存在则创建新文件。
  • "rb":只读模式,打开一个二进制文件用于输入。
  • "wb":只写模式,打开一个二进制文件用于输出,如果文件已存在则清空原有内容,如果文件不存在则创建新文件。
  • "ab":追加模式,打开一个二进制文件用于在文件尾部追加数据,如果文件不存在则创建新文件。
  • "r+":读写模式,打开一个文本文件用于读写,文件必须已存在。
  • "w+":读写模式,打开一个文本文件用于读写,如果文件已存在则清空原有内容,如果文件不存在则创建新文件。
  • "a+":读写模式,打开一个文本文件用于读写,文件不存在则创建新文件,所有写入操作都追加到文件尾部。
  • "rb+":读写模式,打开一个二进制文件用于读写,文件必须已存在。
  • "wb+":读写模式,打开一个二进制文件用于读写,如果文件已存在则清空原有内容,如果文件不存在则创建新文件。
  • "ab+":读写模式,打开一个二进制文件用于读写,文件不存在则创建新文件,所有写入操作都追加到文件尾部。

6.17 文件的读写操作

文件的读写操作可以通过一系列函数来完成,如 freadfwritefgetcfputcfgetsfputs 等。这些函数通常使用缓冲机制来提高性能。

6.18 文件定位

文件定位可以通过 fseek 函数来实现,该函数允许移动文件指针到文件中的任意位置。ftell 函数可以获取文件指针的当前位置。

fseek 函数参数说明:

  • stream:指向 FILE 结构的指针。
  • offset:偏移量,可以是正数或负数。
  • whence:定位基准点,可以是 SEEK_SET(文件开头)、SEEK_CUR(当前文件位置)或 SEEK_END(文件末尾)。

示例代码:

#include <stdio.h>
#include <errno.h>
#include <string.h>int main() {// 打开文件FILE *file = fopen("example.txt", "r+");if (file == NULL) {fprintf(stderr, "打开文件失败: %s\n", strerror(errno));return 1;}// 移动文件指针到文件开头if (fseek(file, 0, SEEK_SET) != 0) {fprintf(stderr, "移动文件指针失败: %s\n", strerror(errno));fclose(file);return 1;}// 获取文件指针的当前位置long position = ftell(file);if (position == -1) {fprintf(stderr, "获取文件指针位置失败: %s\n", strerror(errno));fclose(file);return 1;}printf("文件指针位置: %ld\n", position);// 移动文件指针到文件末尾if (fseek(file, 0, SEEK_END) != 0) {fprintf(stderr, "移动文件指针失败: %s\n", strerror(errno));fclose(file);return 1;}// 获取文件指针的当前位置position = ftell(file);if (position == -1) {fprintf(stderr, "获取文件指针位置失败: %s\n", strerror(errno));fclose(file);return 1;}printf("文件指针位置: %ld\n", position);fclose(file);return 0;
}

6.19 文件错误处理

在进行文件操作时,必须注意处理可能出现的错误。可以使用 ferrorclearerr 函数来帮助诊断和清除错误状态。

示例代码:

#include <stdio.h>
#include <errno.h>
#include <string.h>int main() {// 打开文件FILE *file = fopen("nonexistent.txt", "r");if (file == NULL) {fprintf(stderr, "打开文件失败: %s\n", strerror(errno));return 1;}char buffer[100];size_t bytes_read;// 读取文件bytes_read = fread(buffer, 1, sizeof(buffer), file);if (ferror(file)) {fprintf(stderr, "读取文件失败: %s\n", strerror(errno));fclose(file);return 1;}// 清除错误状态clearerr(file);fclose(file);return 0;
}

文件映射

文件映射是一种高效的数据处理方法,它将文件内容直接映射到进程的虚拟地址空间,使得对文件的操作就像对内存的操作一样简单。文件映射通常通过 mmap 函数来实现。

6.20 使用 mmap 进行文件映射

mmap 函数可以将文件或其他对象映射到内存,映射的内存区域可以直接被读写。

示例代码:

#include <stdio.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>int main() {// 打开文件int fd = open("largefile.dat", O_RDONLY);if (fd == -1) {perror("打开文件失败");return 1;}// 获取文件大小struct stat st;if (fstat(fd, &st) == -1) {perror("获取文件大小失败");close(fd);return 1;}// 映射文件到内存void *addr = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);if (addr == MAP_FAILED) {perror("映射文件失败");close(fd);return 1;}// 处理映射内存// ...// 解映射内存if (munmap(addr, st.st_size) == -1) {perror("解映射内存失败");close(fd);return 1;}// 关闭文件if (close(fd) == -1) {perror("关闭文件失败");return 1;}return 0;
}

总结

本文详细介绍了C语言文件操作中的库函数和系统调用,解释了它们的工作原理、区别和联系,并通过实际示例展示了如何使用这些函数。通过本文的学习,读者应能全面理解C语言文件操作的底层机制,为编写高效、可靠的程序提供有力支持。

希望本文能够帮助读者深入理解和应用C语言中的文件操作技术。如果您有任何进一步的问题或建议,请随时留言交流。

相关文章:

深入C语言文件操作:从库函数到系统调用

引言 文件操作是编程中不可或缺的一部分&#xff0c;尤其在C语言中&#xff0c;文件操作不仅是处理数据的基本手段&#xff0c;也是连接程序与外部世界的重要桥梁。C语言提供了丰富的库函数来处理文件&#xff0c;如 fopen、fclose、fread、fwrite 等。然而&#xff0c;这些库…...

Java序列化

Java序列化 简单来说&#xff1a; 序列化是将对象的状态信息转换为可以存储或传输的形式&#xff08;如字节序列&#xff09;的过程。在 Java 中&#xff0c;通过序列化可以把一个对象保存到文件、通过网络传输到其他地方或者存储到数据库等。最直接的原因就是某些场景下需要…...

基坑表面位移沉降倾斜自动化监测 非接触式一体化解决机器视觉

基于变焦视觉位移监测仪的基坑自动化监测新方案是一种集成了光学、机械、电子、边缘计算、AI识别以及云平台软件等技术的自动化系统。该方案利用变焦机器视觉原理&#xff0c;结合特殊波段成像识别技术和无源靶标&#xff0c;实现了非接触式大空间、多断面、多测点的高精度水平…...

提升效率:精通Windows命令行的艺术

文章目录 引言1. 基本目录操作命令dir&#xff1a;列出目录内容cd&#xff1a;更改目录mkdir 和 rmdir&#xff1a;创建和删除目录 2. 文件操作命令copy&#xff1a;复制文件或目录move&#xff1a;移动或重命名文件/目录del&#xff1a;删除文件 3. 文件查看命令type&#xff…...

ESP32-S3-devKitC-1 点亮板上的WS2812 RGB LED

ESP32-S3-devKitC-1 板上自带了一个RGB LED&#xff0c;型号为 WS2812。 RGB LED 在板上的位置如下图所示。 为了点亮这个WS2812&#xff0c;需要确定这颗RGB LED连接到哪个GPIO上了。 下面是确定GPIO管脚的过程&#xff1a; 1、根据原理图 2、根据PCB布局图&#xff1a; 程…...

python调用matlab函数(内置 + 自定义) —— 安装matlab.engine

文章目录 一、简介二、安装matlab.engine2.1、基于 CMD 安装2.2、基于 MATLAB 安装&#xff08;不建议&#xff09; 三、python调用matlab函数&#xff08;内置 自定义&#xff09; 一、简介 matlab.engine&#xff08;MATLAB Engine API for Python&#xff09;&#xff1a;…...

CAD c# 生成略缩图预览

代码如下&#xff1a; using (Transaction tr currentdb.TransactionManager.StartTransaction()){//当前数据库开启事务using (Database tempdb new Database(false, true)) //创建临时数据库(两个参数&#xff1a;是否创建符号表&#xff0c;不与当前文档关联){try{Bitmap …...

端点鉴别、安全电子邮件、TLS

文章目录 端点鉴别鉴别协议ap 1.0——发送者直接发送一个报文表明身份鉴别协议ap 2.0——ap1.0 的基础上&#xff0c;接收者对报文的来源IP地址进行鉴别鉴别协议ap 3.0——使用秘密口令&#xff0c;口令为鉴别者和被鉴别者之间共享的秘密鉴别协议ap 3.1——对秘密口令进行加密&…...

汽车电子元件的可靠性保障:AEC-Q102认证

AEC-Q102标准的起源与价值 随着汽车电子系统的日益复杂&#xff0c;电子器件必须能够在极端的温度、湿度、振动和电磁干扰等恶劣条件下保持性能。AEC-Q102标准由汽车电子委员会&#xff08;AEC&#xff09;制定&#xff0c;专门针对LED、激光二极管和光电二极管等光电器件&…...

主成分分析法大全(包括stata+matlab)

数据简介&#xff1a;主成分分析&#xff08;Principal Component Analysis&#xff0c;PCA&#xff09;&#xff0c; 是一种统计方法。通过正交变换将一组可能存在相关性的变量转换为一组线性不相关的变量&#xff0c;转换后的这组变量叫主成分。在实际课题中&#xff0c;为了…...

ubuntu+ros新手笔记(五):初探anaconda+cuda+pytorch

深度学习三件套&#xff1a;初探anacondacudapytorch 系统ubuntu22.04 1.初探anaconda 1.1 安装 安装过程参照【详细】Ubuntu 下安装 Anaconda 1.2 创建和删除环境 创建新环境 conda create -n your_env_name pythonx.x比如我创建了一个名为“py312“的环境 conda cre…...

C++ List(双向链表)

是一个线性链表结构&#xff0c;它的数据由若干个节点构成&#xff0c;每一个节点都包括一个 信息块&#xff08;即实际存储的数据&#xff09;、一个前驱指针和一个后驱指针。它无需分配指定 的内存大小且可以任意伸缩&#xff0c;这是因为它存储在非连续的内存空间中&#…...

ASP.NET|日常开发中读写TXT文本详解

ASP.NET&#xff5c;日常开发中读写TXT文本详解 前言一、读取 TXT 文本1.1 使用StreamReader类 二、写入 TXT 文本2.1 使用StreamWriter类 三、文件编码问题3.1 常见编码格式 四、错误处理和性能考虑4.1 错误处理4.2 性能考虑 结束语优质源码分享 ASP.NET&#xff5c;日常开发中…...

【机器学习】在不确定的光影中:机器学习与概率论的心灵共舞

文章目录 概率与统计基础&#xff1a;解锁机器学习的数据洞察之门前言一、概率论基础1.1 概率的基本概念与性质1.1.1 概率的定义1.1.2 样本空间与事件1.1.3 互斥事件与独立事件1.1.4 概率的计算方法 1.2 条件概率与独立性1.2.1 条件概率1.2.2 独立事件 1.3 随机变量1.3.1 随机变…...

【论文笔记】Editing Models with Task Arithmetic

&#x1f34e;个人主页&#xff1a;小嗷犬的个人主页 &#x1f34a;个人网站&#xff1a;小嗷犬的技术小站 &#x1f96d;个人信条&#xff1a;为天地立心&#xff0c;为生民立命&#xff0c;为往圣继绝学&#xff0c;为万世开太平。 基本信息 标题: Editing Models with Task…...

ESP32外设学习部分--UART篇

前言 在我们学习嵌入式的过程中&#xff0c;uart算是我们用的非常多的一个外设了&#xff0c;我们可以用串口打印信息&#xff0c;也可以用于设备通信&#xff0c;总之串口的作用非常多&#xff0c;我们也非常有必要熟练地去掌握这个外设。 uart的配置 uart的参数配置 uart_…...

ssm-day04 mybatis

mybatis是一个持久层框架&#xff0c;针对的是JDBC的优化 简化数据库操作&#xff0c;能进行单表、多表操作&#xff0c;在这个框架下&#xff0c;需要我们自己写SQL语句 Mapper接口和MapperXML文件就相当于Dao和Dao层的实现 通常将xml文件放在resources包下 &#xff0c;放在…...

es中段是怎么合并的

文章目录 1. 段合并的背景2. 合并的方式2.1TieredMergePolicy 的层次结构2.2 层次的基本规则2.3 如何理解层次&#xff08;tier&#xff09;2.4. 合并过程中的层次示例2.5. TieredMergePolicy 的优势2.6. 小结 3. 合并过程中的优化4. 合并的性能考虑5. 使用 API 手动合并6. 合并…...

5、可暂停的线程控制模型

一、需求 在做播放器的时候&#xff0c;很多的模块会创建一个线程&#xff0c;然后在这个线程上跑单独的功能&#xff0c;同时&#xff0c;需要对这个线程进行控制&#xff0c;比如暂停&#xff0c;继续等&#xff0c;如播放器的解码&#xff0c;解封装等&#xff0c;都需要对…...

sql优化--mysql隐式转换

sql隐式转换 在SQL中&#xff0c;隐式转换是数据库自动进行的类型转换&#xff0c;隐式转换可以帮助我们处理不同类型的数据。 比如&#xff0c;数据表的字段是字符串类型的&#xff0c;传入一个整型的数据&#xff0c;也能够运行sql。 sql隐式转换的弊端 sql隐式转换&…...

网络编程(Modbus进阶)

思维导图 Modbus RTU&#xff08;先学一点理论&#xff09; 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议&#xff0c;由 Modicon 公司&#xff08;现施耐德电气&#xff09;于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…...

Vue记事本应用实现教程

文章目录 1. 项目介绍2. 开发环境准备3. 设计应用界面4. 创建Vue实例和数据模型5. 实现记事本功能5.1 添加新记事项5.2 删除记事项5.3 清空所有记事 6. 添加样式7. 功能扩展&#xff1a;显示创建时间8. 功能扩展&#xff1a;记事项搜索9. 完整代码10. Vue知识点解析10.1 数据绑…...

为什么需要建设工程项目管理?工程项目管理有哪些亮点功能?

在建筑行业&#xff0c;项目管理的重要性不言而喻。随着工程规模的扩大、技术复杂度的提升&#xff0c;传统的管理模式已经难以满足现代工程的需求。过去&#xff0c;许多企业依赖手工记录、口头沟通和分散的信息管理&#xff0c;导致效率低下、成本失控、风险频发。例如&#…...

MVC 数据库

MVC 数据库 引言 在软件开发领域,Model-View-Controller(MVC)是一种流行的软件架构模式,它将应用程序分为三个核心组件:模型(Model)、视图(View)和控制器(Controller)。这种模式有助于提高代码的可维护性和可扩展性。本文将深入探讨MVC架构与数据库之间的关系,以…...

镜像里切换为普通用户

如果你登录远程虚拟机默认就是 root 用户&#xff0c;但你不希望用 root 权限运行 ns-3&#xff08;这是对的&#xff0c;ns3 工具会拒绝 root&#xff09;&#xff0c;你可以按以下方法创建一个 非 root 用户账号 并切换到它运行 ns-3。 一次性解决方案&#xff1a;创建非 roo…...

在Ubuntu中设置开机自动运行(sudo)指令的指南

在Ubuntu系统中&#xff0c;有时需要在系统启动时自动执行某些命令&#xff0c;特别是需要 sudo权限的指令。为了实现这一功能&#xff0c;可以使用多种方法&#xff0c;包括编写Systemd服务、配置 rc.local文件或使用 cron任务计划。本文将详细介绍这些方法&#xff0c;并提供…...

linux 下常用变更-8

1、删除普通用户 查询用户初始UID和GIDls -l /home/ ###家目录中查看UID cat /etc/group ###此文件查看GID删除用户1.编辑文件 /etc/passwd 找到对应的行&#xff0c;YW343:x:0:0::/home/YW343:/bin/bash 2.将标红的位置修改为用户对应初始UID和GID&#xff1a; YW3…...

算法:模拟

1.替换所有的问号 1576. 替换所有的问号 - 力扣&#xff08;LeetCode&#xff09; ​遍历字符串​&#xff1a;通过外层循环逐一检查每个字符。​遇到 ? 时处理​&#xff1a; 内层循环遍历小写字母&#xff08;a 到 z&#xff09;。对每个字母检查是否满足&#xff1a; ​与…...

LangChain知识库管理后端接口:数据库操作详解—— 构建本地知识库系统的基础《二》

这段 Python 代码是一个完整的 知识库数据库操作模块&#xff0c;用于对本地知识库系统中的知识库进行增删改查&#xff08;CRUD&#xff09;操作。它基于 SQLAlchemy ORM 框架 和一个自定义的装饰器 with_session 实现数据库会话管理。 &#x1f4d8; 一、整体功能概述 该模块…...

AirSim/Cosys-AirSim 游戏开发(四)外部固定位置监控相机

这个博客介绍了如何通过 settings.json 文件添加一个无人机外的 固定位置监控相机&#xff0c;因为在使用过程中发现 Airsim 对外部监控相机的描述模糊&#xff0c;而 Cosys-Airsim 在官方文档中没有提供外部监控相机设置&#xff0c;最后在源码示例中找到了&#xff0c;所以感…...