【Linux】文件系统:文件fd

news2025/5/15 6:51:50

Alt

🔥个人主页Quitecoder

🔥专栏linux笔记仓

Alt

目录

    • 01.回顾C文件接口
    • 02.系统文件I/O
      • 02.1 open
        • `flags` 参数(文件打开模式)标记位传参
        • 1. 访问模式(必须指定一个)
        • 2. 额外控制标志(可选,可组合使用)
        • 3. `mode` 参数(仅 `O_CREAT` 生效)
      • 02.2 open函数返回值fd(文件描述符)
    • 03.fd理解

01.回顾C文件接口

#include<stdio.h>

int main()
{
    FILE *fp=fopen("log.txt","w");
    if(fp==NULL)
    {
        perror("fopen");
        return 1;
    }
    fclose(fp);
    return 0;
}

我们进行文件操作,前提是我们的代码跑起来了,文件的打开和关闭,是cpu在执行我们的代码

打开文件:本质是进程打开文件

文件没有被打开的时候,存储在磁盘中

一个进程可以打开多个文件,系统中可以启动很多进程,OS内部一定存在大量被打开的文件,操作系统对这些文件进行管理(先描述再组织,类似PCB)

文件=属性+内容

FILE *fp=fopen("log.txt","w");
  1. 如果不存在,则在当前路径下,新建指定的文件
  2. 默认打开文件的时候,会把目标文件清空

在这里插入图片描述
在这里插入图片描述
> 可以用来新建文件,清空文件,先清空再写入

输出重定向一定是文件操作!

打开文件的方式:

 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. The initial file position
 for reading is at the beginning of the file, 
 but output is always appended to the end of the file.
模式描述文件指针位置文件是否会创建文件是否会被截断(清空)
r只读模式,文件必须存在开始位置
r+读写模式,文件必须存在开始位置
w写入模式,文件不存在时会创建,存在时会清空文件开始位置
w+读写模式,文件不存在时会创建,存在时会清空文件开始位置
a追加模式,文件不存在时会创建,存在时内容追加到文件末尾文件末尾
a+读写追加模式,文件不存在时会创建,存在时内容追加到文件末尾开始位置(读取)/文件末尾(写入)

02.系统文件I/O

文件->磁盘->外设->硬件

向文件中写入,本质是向硬件中写入,用户没有权利直接写入,通过OS写入,OS必须给我们提供系统调用

fopen/fwrite/fread/fprintf/scanf/printf/cin/cout 我们用的c/c++都是对系统调用接口的封装

02.1 open

在这里插入图片描述

open 是 Unix/Linux 系统中用于打开或创建文件的系统调用,位于 fcntl.h 头文件中。它用于以不同的模式访问文件,如只读、写入、追加等。

1. open 函数原型
在 C 语言中,open 的函数原型如下:

#include <fcntl.h>  // 文件控制选项
#include <sys/types.h>  // 类型定义
#include <sys/stat.h>  // 文件属性
#include <unistd.h>  // 通用 API

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

2. 参数解析

  • pathname:要打开的文件路径。
  • flags:指定文件的访问模式(只读、读写等)和其他选项(创建文件、截断等)。
  • mode:用于设置新文件的权限(仅当 O_CREAT 选项被使用时有效),通常采用 06440666 形式。

3. 返回值

  • 成功:返回一个文件描述符(非负整数),用于后续的 readwriteclose 操作
  • 失败:返回 -1,并设置 errno 变量来指示错误类型。

flags 参数(文件打开模式)标记位传参

在系统调用(如 open())中,flags 是一个 位掩码(bitmask),用于控制函数的行为。例如,在 open() 中,flags 用于指定文件的打开模式(只读、只写、读写等)以及额外的选项(创建、追加、非阻塞等)。

位掩码 是指使用二进制位的不同组合来表示多种选项,这样可以通过按位或 (|) 来组合多个标志,而不会相互影响

1. 访问模式(必须指定一个)

访问模式决定了文件的读写权限,这三者不能同时使用,否则会报错。

标志值(十六进制)说明
O_RDONLY0x0000只读模式(Read Only)
O_WRONLY0x0001只写模式(Write Only)
O_RDWR0x0002读写模式(Read & Write)

示例

int fd = open("file.txt", O_RDONLY);  // 以只读模式打开文件
int fd = open("file.txt", O_WRONLY);  // 以只写模式打开文件
int fd = open("file.txt", O_RDWR);    // 以读写模式打开文件

2. 额外控制标志(可选,可组合使用)

这些标志可以与访问模式组合使用,以改变 open() 的行为。

标志值(十六进制)说明
O_CREAT0x0040若文件不存在,则创建新文件(需要 mode 参数)
O_EXCL0x0080O_CREAT 组合,文件必须不存在,否则失败
O_TRUNC0x0200若文件已存在,则清空文件内容
O_APPEND0x0400追加模式,写入时自动跳到文件末尾
O_NONBLOCK0x0800非阻塞模式打开文件(常用于设备文件、网络通信)
O_SYNC0x101000使 write 操作同步到磁盘,保证数据立即写入
O_NOFOLLOW0x20000如果文件是符号链接,则 open() 失败
3. mode 参数(仅 O_CREAT 生效)

flags 包含 O_CREAT 时,需要提供 mode 参数,表示新建文件的权限,例如:

open("newfile.txt", O_WRONLY | O_CREAT, 0644);

其中 0644 代表:

  • 0:八进制数前缀
  • 6110):用户(拥有者)可读可写
  • 4100):组(Group)只读
  • 4100):其他人(Others)只读

如何组合 flags
由于 flags位掩码(bitmask),可以使用按位或 | 运算符来组合多个标志。例如:

int fd = open("file.txt", O_RDWR | O_CREAT | O_TRUNC, 0644);
  • O_RDWR(读写模式)
  • O_CREAT(如果文件不存在,则创建)
  • O_TRUNC(如果文件已存在,则清空内容)

等价于:

flags = 0x0002 | 0x0040 | 0x0200;  // 计算出的十六进制值

flags 具体的二进制表示
假设 flags 组合如下:

int flags = O_RDWR | O_CREAT | O_APPEND; 

如果 O_RDWR = 0x0002O_CREAT = 0x0040O_APPEND = 0x0400,那么它们的二进制表示如下:

O_RDWR    = 0000 0000 0000 0010  (0x0002)
O_CREAT   = 0000 0000 0100 0000  (0x0040)
O_APPEND  = 0000 0100 0000 0000  (0x0400)
--------------------------------
组合后    = 0000 0100 0100 0010  (0x0442)

open() 处理 flags 时,它会解析这个二进制值,并执行相应的操作。

  • flagsopen()核心参数,用于控制文件的访问模式和特殊行为。
  • 访问模式(O_RDONLYO_WRONLYO_RDWR必须指定一个
  • 可以通过按位或 | 组合多个控制标志(如 O_CREATO_TRUNCO_APPEND)。
  • mode 参数用于 O_CREAT,指定新文件的权限,如 0644
  • open() 返回文件描述符(fd),失败时返回 -1 并设置 errno

这种flags的传递位图标记位的方法在OS系统调用接口中很常见,我们可以自己设计一个传递位图标记位的函数:

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

#define ONE 1       //1 0000 0001
#define TWO (1<<1)   //2 0000 0010
#define THREE (1<<2) //4 0000 0100
#define FOUR (1<<3)  //8 0000 1000


void print(int flag)
{
    if(flag&ONE)
        printf("one\n");
    if(flag&TWO)
        printf("two\n");
    if(flag&THREE)
        printf("three\n");
    if(flag&FOUR)
        printf("four\n");
}

int main()
{
    print(ONE);
    printf("\n");
   
    print(TWO);
    printf("\n");
    

    print(THREE);
    printf("\n");
    
    print(ONE|TWO);
    printf("\n");
    
    print(ONE|THREE);
    printf("\n");
    
    print(ONE|TWO|THREE|FOUR);
    printf("\n");
    
    
    return 0;
}

演示了如何使用位运算来检查不同的标志(flag)。程序中的关键部分是 print 函数,它检查传入的 flag 参数,并根据不同的位值输出相应的文本。

让我们逐步分析每个部分。


宏定义

#define ONE 1       //1 0000 0001
#define TWO (1<<1)   //2 0000 0010
#define THREE (1<<2) //4 0000 0100
#define FOUR (1<<3)  //8 0000 1000

这部分定义了四个宏,每个宏的值都代表一个特定的二进制位:

  • ONE = 1 :二进制 0000 0001,表示第 0 位(从右向左数)。
  • TWO = 2 :二进制 0000 0010,表示第 1 位。
  • THREE = 4 :二进制 0000 0100,表示第 2 位。
  • FOUR = 8 :二进制 0000 1000,表示第 3 位。

使用 1 << n 来左移 1 位 n 次,从而生成一个表示 2 的幂的二进制值。


print 函数

void print(int flag)
{
    if(flag&ONE)
        printf("one\n");
    if(flag&TWO)
        printf("two\n");
    if(flag&THREE)
        printf("three\n");
    if(flag&FOUR)
        printf("four\n");
}

print 函数通过位运算 &(按位与运算)检查给定 flag 中每一位是否设置为 1。如果某一位为 1,就会输出相应的文本。

  • flag & ONE:检查 flag 的第 0 位(ONE)。
  • flag & TWO:检查 flag 的第 1 位(TWO)。
  • flag & THREE:检查 flag 的第 2 位(THREE)。
  • flag & FOUR:检查 flag 的第 3 位(FOUR)。

输出说明:

  1. print(ONE) 传入 ONE(即 1,二进制 0000 0001),因此检查到第 0 位为 1,输出 one
  2. print(TWO) 传入 TWO(即 2,二进制 0000 0010),因此检查到第 1 位为 1,输出 two
  3. print(THREE) 传入 THREE(即 4,二进制 0000 0100),因此检查到第 2 位为 1,输出 three
  4. print(ONE | TWO) 传入 ONE | TWO(即 1 | 2 = 3,二进制 0000 0011),因此第 0 位和第 1 位都为 1,输出 onetwo
  5. print(ONE | THREE) 传入 ONE | THREE(即 1 | 4 = 5,二进制 0000 0101),因此第 0 位和第 2 位都为 1,输出 onethree
  6. print(ONE | TWO | THREE | FOUR) 传入 ONE | TWO | THREE | FOUR(即 1 | 2 | 4 | 8 = 15,二进制 0000 1111),因此所有四个标志位都为 1,输出 onetwothreefour

one

two

three

one
two

one
three

one
two
three
four

这个例子很有用,展示了如何使用位操作进行标志位管理,尤其是在处理多个选项或功能时


4. openfopen 的区别

对比项open(系统调用)fopen(标准库函数)
头文件<fcntl.h><stdio.h>
返回值文件描述符(intFILE* 指针
模式需要手动指定 flags类似 "r", "w", "a"
缓冲无缓冲,直接访问内核有缓冲,性能更优
适用场景底层 I/O 操作高级文件读写操作
  • 如果只是进行简单的文件读写,建议使用 fopen,因为它提供了缓冲,效率更高
  • 如果需要进行更底层的文件控制(如非阻塞、文件锁定等),则使用 open

02.2 open函数返回值fd(文件描述符)

write函数原型:

#include <unistd.h>

ssize_t write(int fd, const void *buf, size_t count);
int main()
{
    umask(0);
    int fd=open("file.txt",O_WRONLY | O_CREAT,0666);
    if(fd<0)
    {
        perror("open");
        return 1;
    }
    const char *message = "hello linux\n";
    write(fd,message,strlen(message));
    close(fd);
    
    return 0;
}

在这里插入图片描述
此时如果我们重新写入aaaaa:

在这里插入图片描述
这里的文件内容老的没有被清空,这里跟open那里fd传入flags参数有关,我们这里传入O_TRUNC,每次打开文件时清空即可

在这里插入图片描述

int fd=open("file.txt",O_WRONLY | O_CREAT | O_TRUNC,0666);

写方式打开,不存在就创建,存在就先清空!

在认识返回值之前,先来认识一下两个概念: 系统调用 和 库函数

上面的 fopen fclose fread fwrite 都是C标准库当中的函数,我们称之为库函数(libc)。
而, open close read write lseek 都属于系统提供的接口,称之为系统调用接口

在这里插入图片描述

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

接下来看fd

fd是open的返回值,也是文件描述符,我们这里设置代码来打印出它的值

int main()
{
    int fda=open("loga.txt",O_WRONLY|O_CREAT|O_APPEND,0666);
    printf("fda:%d\n",fda);
    int fdb=open("logb.txt",O_WRONLY|O_CREAT|O_APPEND,0666);
    printf("fdb:%d\n",fdb);
    int fdc=open("logc.txt",O_WRONLY|O_CREAT|O_APPEND,0666);
    printf("fdc:%d\n",fdc);
    int fdd=open("logd.txt",O_WRONLY|O_CREAT|O_APPEND,0666);
    printf("fdd:%d\n",fdd);
    return 0;
}

在这里插入图片描述
文件描述符数字为3 4 5 6

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

C 语言的标准流与操作系统的文件描述符是关联的。

  • 标准输入(stdin):与文件描述符 0 相关联。
  • 标准输出(stdout):与文件描述符 1 相关联。
  • 标准错误(stderr):与文件描述符 2 相关联

这些文件描述符在程序启动时由操作系统自动分配并打开,且在大多数情况下它们指向终端或控制台。如果没有显式地进行文件重定向(例如使用freopen 或命令行中的重定向符号),这些文件描述符就会继续指向终端

ssize_t write(int fd, const void *buf, size_t count);

那么我们可以直接往显示器上写入:

const char *message = "aaaaa\n";
write(1,message,strlen(message));

在这里插入图片描述

03.fd理解

在这里插入图片描述
系统中有进程被task_struct管理,有很多被打开的文件,struct file 是操作系统用来表示打开文件的主要数据结构。每当一个文件被打开时,操作系统会创建一个 struct file 对象,并将其与文件描述符关联,对象之间通过双向链表连接

struct file {
    struct file_operations *f_op;  // 文件操作的指针
    void *private_data;            // 私有数据,用于存储文件的额外信息(如文件特定的数据结构)
    unsigned long f_flags;         // 文件标志,描述文件的访问模式(如只读、只写、追加等)
    struct inode *f_inode;         // 文件的 inode 节点,包含文件的元数据
    off_t f_pos;                   // 文件指针,记录当前文件的读写位置
};

struct file有指向它的缓存,磁盘中文件,属性来初始化struct file,内容加载到缓存中,未来想读修改写入直接在缓存总写入,最后刷新到磁盘中,所以对文件的管理转化为对内核struct file进行管理

那么系统中有很多的进程,右边有很多被打开的文件,那么哪些文件对应哪些进程呢?

进程是可以打开多个文件的,操作系统在PCB里存在一个属性,这个属性叫做struct files_struct *files

在这里插入图片描述

struct files_struct 包含一个数组,数组有对应的下标,进程需要找到一个文件,最终只需要把数组的下标返回给上层,上层只要拿着int fd就可以访问文件了!

所以文件描述符fd的本质是内核的进程的,文件映射关系数组的下标

所以文件一旦打开,我们发现,write,read,close都需要参数fd,一旦fd传入,操作系统就能知道你要访问当前系统的哪个文件

所以读文件就是把缓存中的内容拷贝到应用层,无论读写都必须在合适的时候让0S把文件的内容读到文件缓冲区中,哪怕只修改一个字节,也需要把文件内容读到缓冲区中,再刷到磁盘中

open在干什么呢?

  1. 创建file
  2. 开辟文件缓冲区的空间,加载文件数据(延后)
  3. 查进程的文件措述符表
  4. file地址,填入对应的表下标中
  5. 返回下标

我们已经理解了什么是fd,我们前面提到0 1 2是默认打开了,分别对应键盘,显示器,显示器,三个硬件,如何理解它呢?

我们需要理解,linux,一切皆为文件

在这里插入图片描述
在linux层面上他是怎么做到的呢?

对于每一种设备,我们需要关心的是它的属性和操作方法

最重要的是关注它的操作方法,对于键盘来讲,需要有自己的读方法,写方法,对于显示器,也要有自己的读方法,写方法。冯诺依曼体系中,键盘作为外设,那么这个写方法设置为空函数,显示器对应的读方法也没办法实现

不同的设备,每一种设备的操作方法一定是不一样的,这一层是由驱动层来完成的

每一个被打开的设备,在操作系统层面,为设备构建struct file,虽然底层的方法不同,但是我可以把参数和返回值设为类似的,这里OS设置函数指针。所以如果我们想要访问键盘,找到键盘的struct file,调用read,从struct file视角往上看,上层看到所有的设备一切皆文件

这里是c语言实现的多态技术,进程统一认为struct file

这里的文件层,我们成为虚拟文件系统

虚拟文件系统(VFS,Virtual File System)是操作系统中的一个抽象层,它为不同类型的文件系统(如ext4、NTFS、FAT、NFS 等)提供了一个统一的接口。通过VFS,操作系统能够以一致的方式访问和管理不同类型的文件系统,无论是本地磁盘文件系统还是网络文件系统。这使得文件系统的实现与用户或应用程序的使用方式解耦,增强了操作系统的灵活性和可扩展性

在这里插入图片描述
在操作系统内访问文件时,系统只认文件描述符

那么如何理解c语言通过FILE*访问文件呢?

FILE*:是 C 标准库提供的文件操作接口,它是一个指向 FILE 结构的指针。C 标准库通过 FILE* 为程序员提供了一套更为友好的文件操作函数,如 fopen、fread、fwrite、fclose 等。FILE* 实际上是对文件描述符的封装,提供了缓冲区管理、错误处理等功能

在这里插入图片描述
c语言为什么要这么做?

对于系统调用,不同系统调用接口不一样,这样的代码不具有跨平台性。所有的语言都想有跨平台性,所有的语言对不同平台系统的系统调用进行封装,不同语言封装的时候,文件接口就有差别了

在这里插入图片描述

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

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

相关文章

电脑系统损坏,备份文件

一、工具准备 1.U盘&#xff1a;8G以上就够用&#xff0c;注意会格式化U盘&#xff0c;提前备份U盘内容 2.电脑&#xff1a;下载Windows系统并进行启动盘制作 二、Windows启动盘制作 1.微软官网下载启动盘制作工具微软官网下载启动盘制作工具https://www.microsoft.com/zh-c…

Python网络运维自动化:从零开始学习NetDevOps

零基础入门NetDevOps&#xff0c;让网络运维更简单、更高效。 Python网络运维自动化 1.从理论到实战&#xff1a;从基础理论入手&#xff0c;通过实战案例教学&#xff0c;手把手教读者掌握Python网络运维自动化&#xff0c;解决运维工作中的日常问题&#xff0c;提升运维效率…

公网远程家里局域网电脑过程详细记录,包含设置路由器。

由于从校内迁居小区,校内需要远程控制访问小区内个人电脑,于是早些时间刚好自己是电信宽带,可以申请公网ipv4不需要花钱,所以就打电话直接申请即可,申请成功后访问光猫设备管理界面192.168.1.1,输入用户名密码登录超管(密码是网上查下就有了)设置了光猫为桥接模式,然后…

网络安全示意图 网络安全路线图

其实网络安全本身的知识点并不算难&#xff0c;但需要学的东西比较多&#xff0c;如果想要从事网络安全领域&#xff0c;肯定是需要系统、全面地掌握清楚需要用到的技能的。 自学的方式基本是通过看视频或者相关的书籍&#xff0c;不论是什么方法&#xff0c;都是很难的&#…

【多线程异步和MQ有什么区别?】

多线程异步和MQ有什么区别? 多线程异步MQ(消息队列)多线程异步与MQ的区别多线程异步 概念: 多线程异步是指在单个应用程序内部创建和管理多个线程,这些线程并行处理任务。 多线程主要用于提升应用程序的性能,特别是在处理计算密集型任务(如科学计算、图像处理、数据分…

Annie导航2.0 新增加5个模版 开源免授权

新增5个模版 修复部分模版样式问题 采用最新技术tinkphp8.0 php8.1 mysql5.7 Funadmin框架 后台一键式统计访问人数 网站设置 分类设置 网站管理 工具管理 友情链接 广告管理 [color=var(–comiis-color)]联系方式 主题管理 配置多套模版随意切换 已更新市面上热门的几个模版

Spring AI发布!让Java紧跟AI赛道!

1. 序言 在当今技术发展的背景下&#xff0c;人工智能&#xff08;AI&#xff09;已经成为各行各业中不可忽视的重要技术。无论是在互联网公司&#xff0c;还是传统行业&#xff0c;AI技术的应用都在大幅提升效率、降低成本、推动创新。从智能客服到个性化推荐&#xff0c;从语…

[文末数据集]ML.NET库学习010:URL是否具有恶意性分类

文章目录 ML.NET库学习010:URL是否具有恶意性分类项目主要目的和原理项目概述主要功能和步骤总结数据集地址ML.NET库学习010:URL是否具有恶意性分类 项目主要目的和原理 项目主要目的: 本项目的目的是通过分析URL的特征,构建一个机器学习模型来判断给定的URL是否具有恶意…

百度地图接入DeepSeek技术解析:AI如何重塑地图搜索体验?

百度地图接入DeepSeek技术解析&#xff1a;AI如何重塑地图搜索体验&#xff1f; 百度地图接入DeepSeek技术解析&#xff1a;AI如何重塑地图搜索体验&#xff1f;引言一、技术背景与核心能力1.1 DeepSeek的技术优势1.2 百度地图API的技术底座 二、技术实现路径2.1 系统架构设计2…

C语言——深入理解指针(2)(数组与指针)

文章目录 数组名的理解使用指针访问数组一维数组传参的本质冒泡排序二级指针指针数组指针数组模拟二维数组 数组名的理解 之前我们在使用指针访问数组内容时&#xff0c;有这样的代码&#xff1a; int arr[10]{1,2,3,4,5,6,7,8,9,10}; int* p&arr[0];这里我们使用&ar…

Open-WebUI官方部署文档

Github地址&#xff1a;GitHub - open-webui/open-webui: User-friendly AI Interface (Supports Ollama, OpenAI API, ...) 打开 WebUI &#x1f44b; 如果你是零基础的小白&#xff0c;不知道什么是DeepSeek的话&#xff1f;不知道如何本地化部署&#xff0c;我强烈建议先看…

爬虫破解网页禁止F12

右击页面显示如下 先点击f12再输入网址&#xff0c;回车后没有加载任何数据 目前的一种解决方法&#xff1a; 先 AltD &#xff0c;再 CtrlShifti

Xshell连接虚拟机ubuntu,报错(port 22): Connection failed.

Connecting to 192.168.37.131:22... Could not connect to 192.168.37.131 (port 22): Connection failed. 虚拟机ubuntu 可以ping通&#xff0c;但就是连接不上。 先后排查了&#xff0c; 1. 网络适配器是否被禁用 2.设置虚拟机网络适配器的网络连接模式为桥接模式&#xf…

浏览器报错:无法访问此网站 无法找到xxx.xxx.net的DNS地址。正在诊断该问题。尝试运行Windows网络诊断。DNS_PROBE_STARTED

&#x1f91f;致敬读者 &#x1f7e9;感谢阅读&#x1f7e6;希望我的文章能帮到您&#x1f7ea;如有兴趣可点关注了解更多内容 &#x1f4d8;博主信息 点击标题&#x1f446;有惊喜 &#x1f4c3;文章前言 &#x1f537;文章均为学习和工作中整理的笔记&#xff0c;分享记录…

2024年国赛高教杯数学建模C题农作物的种植策略解题全过程文档及程序

2024年国赛高教杯数学建模 C题 农作物的种植策略 原题再现 根据乡村的实际情况&#xff0c;充分利用有限的耕地资源&#xff0c;因地制宜&#xff0c;发展有机种植产业&#xff0c;对乡村经济的可持续发展具有重要的现实意义。选择适宜的农作物&#xff0c;优化种植策略&…

CentOS/RHEL如何更换国内Yum源

在国内使用CentOS或RHEL系统时&#xff0c;默认的Yum源是国外的&#xff0c;这可能导致软件包的下载速度慢&#xff0c;甚至出现连接超时的问题。为了解决这个问题&#xff0c;我们可以将Yum源切换到国内的镜像源&#xff0c;从而大大提高软件包的下载速度和稳定性。 本文将详…

A9. Jenkins Pipeline自动化构建,飞书通知

怎么收集服务部署信息?【前置】首先Python如何操作JSON数据如何记录部署信息,什么时机统计?如何下发某一服务统计信息 ?那么怎么创建飞书通知机器人呢?编写飞书通知脚本总结下面我们接着上一篇文章《A8. Jenkins Pipeline自动化部署过程,多模块远程服务协调实战》继续往下…

利用 OpenCV 进行棋盘检测与透视变换

利用 OpenCV 进行棋盘检测与透视变换 1. 引言 在计算机视觉领域&#xff0c;棋盘检测与透视变换是一个常见的任务&#xff0c;广泛应用于 摄像机标定、文档扫描、增强现实&#xff08;AR&#xff09; 等场景。本篇文章将详细介绍如何使用 OpenCV 进行 棋盘检测&#xff0c;并…

DeepMind发布Matryoshka(套娃)量化:利用嵌套表示实现多精度LLM的低比特深度学习

本文将介绍 Google DeepMind 提出的 Matryoshka 量化技术&#xff0c;该技术通过从单个大型语言模型 (LLM) 实现多精度模型部署&#xff0c;从而革新深度学习。我们将深入研究这项创新技术如何提高 LLM 的效率和准确性。 随着深度学习模型在规模和复杂度上持续增长&#xff0c…

Java-数据结构-(HashMap HashSet)

一、Tree和Hash的区别 在上一篇文章中&#xff0c;我们讲到了"TreeMap"和"TreeSet"&#xff0c;但当我们刷题的时候却会发现&#xff0c;实际应用Map和Set时&#xff0c;却常常都只会用"HashMap"和"HashSet"&#xff0c;这是为什么呢…