Linux文件操作基础

news2024/12/14 6:42:25

1.引入

在Linux第一章提到过, 在Linux中,一切皆文件,而文件由文件内容和文件属性组成,在C语言中可以 使用相应的接口打开文件,例如 fopen 函数

文件最开始在磁盘中,但是因为磁盘的速度远低于CPU的执行速度,根据冯诺依曼体系结构,CPU与内 存进行交互,所以可以推出文件要被程序读取,就需要与程序加载到内存变成进程一样,文件也需要加 载到内存,而加载到内存中的文件包括其内容和属性,内容可以类比为进程的代码和数据,而因为操作 系统也需要管理加载到内存的文件,所以文件属性也被存储到一个结构中,可以类比为进程的PCB

所以,在研究Linux文件系统部分主要研究两种文件:

1. 加载到内存的文件

2. 存储在磁盘中的文件

2.回顾C语言文件操作

在C语言中,常见的处理文件的步骤如下:

1. 打开文件: fopen 函数

2. 读取/写入内容: fwrite 函数或者 fread函数

3. 关闭文件: fclose 函数

示例代码如下:

#include <stdio.h>
#include <string.h>
 
int main()
{
    // 以写的方式打开
    FILE* fp = fopen("test.txt", "w");
    // 向文件中写数据
    const char* content = "hello linux\n";
    fwrite(content, 1, strlen(content), fp);
    // 关闭文件
    fclose(fp);
 
    return 0;
}

在上面的代码中,使用fopen函数以w的方式打开当前目录下名为test.txt的文件,通过fwrite函数向文件中写入一个字符串,最后调用fclose函数关闭文件

在C语言部分学到过,一切以w方式打开的文件,不论是否向该文件写入数据,都会优先清空文件中的数据,而如果指定的文件不存在,不论之后是否会写入都会先创建文件

除了w方式以外,还有一个a方式,以a方式打开的文件,不论是否向该文件写入数据,都不会清空数据,如果需要写入,则是在文件已有的内容之后进行追加,同样如果指定的文件不存在,不论之后是否会写入都会先创建文件

除了上面的操作性知识回顾以外,在C语言中也学到,默认情况下,程序在启动时默认会开启三个流:

  1. stdin:标准输入流,一般认为是从键盘文件读取
  2. stdout:标准输出流,一般认为是写入显示器
  3. stderr:标准输出流,一般认为是写入日志文件或者写入显示器

2.1系统调用接口

在操作系统基础部分提到过,操作系统上层存在一个系统调用接口部分,实际上C语言提供的文件操作函数都是语言级的函数,对于不同的操作系统,系统调用接口部分也会提供不同的函数供上层调用,为了更加便捷,C语言针对操作系统封装了对应的系统接口形成对应的函数,例如在Linux中,C语言的fopen实际上封装的就是Linux系统接口open函数

2.1.1   open函数

根据Linux的操作手册,下面是open 函数的两种函数原型:

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

参数解释:

  1. pathname:文件路径名
  2. flags:打开文件的方式
  3. mode:创建文件是,文件所拥有的权限

需要注意的是,对于第一种方式,因为没有参数可以传递文件创建时的权限,所以一般不会用第一种方式创建文件,更多得可能还是使用第二种方式

返回值解释:

两个函数都返回文件描述符,该值唯一代表一个加载到内存的文件

在Linux中,flags有下面几种常用的值,这些值都是被定义的宏:

1.  O_RDONLY:只读模式
2.  O_WRONLY:只写模式
3.  O_RDWR:读写模式
4.  O_TRUNC:覆写模式
5.  O_CREAT:文件不存在时创建文件
6.  O_APPEND:追加模式

注意,上面的所有模式只有给出的文字描述中的一种效果,没有其他效果

在给open函数的flags参数传递实参时,如果只传递五种模式的其中一种,一个参数完全可以胜任,但是如果想一次传递多个模式,比如以只写并且文件不存在时创建文件模式打开,此时就涉及到两个模式,一个形参如果通过直接赋值的形式,则无法同时识别两个模式。为了解决这个问题,实际上在Linux中,这个flags是个32个比特位的位图结构,此时传递参数就可以按照位运算的方式传递,在open函数中,只需要判断位图中为1的部分就可以知道指定了哪些模式,下面以一个例子帮助理解这一个思路:

  1. 定义一些宏模拟上面的模式
// 1左移0位,结果还是1(二进制位01)
#define AONE (1 << 0) 
// 1左移1位,结果是2(二进制位10)
#define ATWO (1 << 1)
// 1左移2位,结果是4(二进制100)
#define ATHREE (1 << 2)
  1. 创建函数,参数设置为一个整数,内容为打印指定模式
void print(int flag)
{
    // 与运算取出二进制中的1判断指定模式是否选择
    if (flag & AONE)
    {
        printf("AONE模式\n");
    }
    if (flag & ATWO)
    {
        printf("ATWO模式\n");
    }
    if (flag & ATHREE)
    {
        printf("ATHREE模式\n");
    }
}

测试:

#include <stdio.h>
 
int main()
{
    // 1种模式
    print(AONE);
    printf("************\n");
    // 2种模式,将为0的比特位置为1
    print(AONE | ATWO);
    printf("************\n");
    // 3种模式
    print(AONE | ATWO | ATHREE);
}
 
输出结果:
AONE模式
************
AONE模式
ATWO模式
************
AONE模式
ATWO模式
ATHREE模式

2.1.2.read函数和write函数

在Linux中,read函数和write函数读和写的系统调用接口,其原型如下:

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

参数解释:

1. fd:文件描述符,对应open函数返回值

2. buf:指向指定数组,对于read函数来说,代表存入读取到的内容的起始地址;对于write函 数来说,代表待输出的内容的起始地址

3. count:代表期望内容个数,对于read函数来说,代表最大读取内容的个数;对于write函数 来说,表示最大输出内容的个数

返回值解释: 两个函数均返回实际的内容个数,对于read函数来说,代表实际读取内容的个数;对于write函数来 说,表示实际输出内容个数

2.1.3  close 函数

int close(int fd);

参数解释:fd代表文件描述符,与open函数的返回值对应

返回值解释:0代表关闭成功,小于0代表失败

2.2模拟C语言接口

有了上面的铺垫,现在考虑open函数的使用模拟w的方式,根据前面C语言中w方式的描述:以写模式打开并且不存在指定文件时创建该文件,若指定文件中有内容就清除文件内容,需要使用到只写模式、文件不存在时创建模式和覆写模式

先观察三个模式依次搭配的特点:

  • O_WRONLY
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
 
int main()
{
    // 以只写模式打开文件
    int fd = open("test.txt", O_WRONLY);
    // 向文件中写入
    const char* content = "hello linux\n";
    int num = write(fd, content, strlen(content));
    printf("%d\n", num);
    // 关闭文件
    close(fd);
 
    return 0;
}

如果此时将写入的内容变短为3个字符,观察下面代码的运行结果:

#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
 
int main()
{
    // 以只写模式打开文件
    int fd = open("test.txt", O_WRONLY);
    // 向文件中写入
    const char* content = "bye";
    write(fd, content, strlen(content));
    // 关闭文件
    close(fd);
 
    return 0;
}

可以看到,只写模式打开一个有内容的文件默认不会清除原始内容,而是覆盖写

O_TRUNC和O_WRONLY

#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
 
int main()
{
    // 以只写模式打开文件
    int fd = open("test.txt", O_WRONLY | O_TRUNC);
    // 向文件中写入
    const char* content = "hello\n";
    write(fd, content, strlen(content));
    // 关闭文件
    close(fd);
 
    return 0;
}

可以看到加了O_TRUNC宏后,就可以达到打开文件后不论文件是否有内容都会先清空再写入内容

O_TRUNC、O_WRONLY和O_CREAT

前面两个选项都只展示了在有指定文件的情况下正常运行,但是C语言的fopen函数以w方式打开 指定文件,当该文件不存在会自动创建,所以此时就需要在系统调用接口加上O_CREAT,例如下面 的代码:

删除当前目录的test.txt文件后执行上面的代码:

可以看到会自动创建test.txt文件再写入指定的内容

此时就简单实现了C语言中的w方式打开的效果,但是此时创建的test.txt文件与直接使用 touch创建的文件有点出入

2.3  open函数与文件权限

前面使用到了open函数的第一个版本,现在考虑open函数第二个版本,这个函数可以传递第三个参 数,该参数表示文件创建时拥有的权限,传递权限八进制值

先观察使用第一个版本创建出的文件拥有的权限

 #include <stdio.h>
 #include <string.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <fcntl.h>
 #include <unistd.h>
 int main()
 {
    int id = open("test.txt", O_CREAT);
    close(id);
    return 0;
 }

运行程序结果如下:

可以看到创建出来的文件所拥有的权限是错乱的,尤其是除了所有者以外的权限,为了避免出现这个情况,就需要使用第二个版本的open函数

#include <stdio.h>
 #include <string.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <fcntl.h>
 #include <unistd.h>
int main()
 {
    int id = open("test.txt", O_CREAT, 0666);
    close(id);
    return 0;
 }

结果如下:

可以看到此时文件权限就是正常的,但是因为存在文件权限掩码umask,所以其值并不是代码中设置的 0666(对应为-rw-rw-rw-),当前系统的文件权限掩码可以通过umask指令查看,默认为0002

如果不希望在程序中创建的文件所拥有的权限受到系统umask影响,可以在创建文件之前使用umask函 数设置初始的文件权限掩码为0:

#include <stdio.h>
 #include <string.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <fcntl.h>
 #include <unistd.h>
 int main()
 {
    umask(0);
    int id = open("test.txt", O_CREAT, 0666);
    close(id);
    return 0;
 }

运行后观察到当前就是程序中指定的0666权限:

3.文件描述符

前面的系统调用接口函数中,四个函数均涉及到了文件描述符,该描述符在Linux中是对每一个加载到内 存的唯一标识,打印指定的文件观察open函数返回值:

#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
 
int main()
{
    // 以只写模式打开文件
    int fd = open("test.txt", O_WRONLY | O_TRUNC | O_CREAT);
    printf("%d\n", fd);
    // 关闭文件
    close(fd);
 
    return 0;
}
 
输出结果:
3

当open函数打开文件成功时返回-1,否则返回打开的文件对应的文件描述符,为了知道何 为文件描述符,这里就需要深入了解在Linux具体是如何描述和管理文件的

首先,有了前面学习进程的基础可以知道每一个进程需要被管理就需要先描述再组织,而描述对应的就 是进程PCB(task_struct),组织就是双向链表,对于文件也是如此,描述对应的就是struct file,组织也是双向链表

但是,如果直接让进程访问文件结构file就会增加耦合度,导致操作系统的管理工作会变得繁重,所以 在内存中,进程结构在单独的一个区域,文件结构也在单独的一个区域,而为了进程可以访问到文件, 进程结构中就存在一个结构体指针struct files_struct *files,该结构体指针类型是struct files_struct *,所谓的files_struct就是将文件和进程建立连接的结构,该结构中存在一个属 性:struct file * fd_array[NR_OPEN_DEFAULT],该数组的每一个成员就是指向每一个文件 file结构的指针,因为是数组,所以可以通过下标访问指定的元素,在当前这个条件下,访问到的就是 指向每一个文件file结构的指针

所以所谓的文件描述符,就是fd_array数组的下标,示意图如下:

此时就会有第二个问题:为什么在程序中打开的文件默认下标是3,错误是-1,中间的0、1和2表示什 么?

前面提到,在C语言程序启动时,会自动加载3种文件流:

1. stdin:标准输入流,一般认为是从键盘文件读取

2. stdout:标准输出流,一般认为是写入显示器

3. stderr:标准输出流,一般认为是写入日志文件或者写入显示器

在Linux手册中,这三个流的原型如下:

#include <stdio.h>
 
extern FILE *stdin;
extern FILE *stdout;
extern FILE *stderr;

可以看到三者均是FILE类型,这个类型实际上是语言级上的封装,因为在Linux中文件描述符是访问文 件的唯一方式,所以C语言的接口想访问文件就必须要访问到指定文件的文件描述符,所以FILE结构中 一定可以有文件描述符属性,根据下面代码可以验证(下面的代码中_fileno对应的就是文件描述 符):

#include <stdio.h>
 
int main()
{
    printf("%d\n", stdin->_fileno);
    printf("%d\n", stdout->_fileno);
    printf("%d\n", stderr->_fileno);
 
    return 0;
}
 
输出结果:
0
1
2

所以,之所以显式打开的文件对应的文件描述符为3是因为默认打开的三个文件占用了fd_array数组前面三个空间

4.如何理解Linux下一切皆文件

前面提到多次「在Linux下一切皆文件」,对于保存在计算机硬盘中的文件来说,说其是文件再合适不 过,但是对于硬件来说,如果再说硬件是文件难免有些不妥,但是如果硬件不属于文件,那么就不会出 现「在Linux下一切皆文件」的表述,所以硬件为什么在Linux下硬件也算文件

要理解为什么在Linux下硬件也算文件,需要先回顾操作系统的作用。在开始进程部分之前,提到过操作 系统实际上是一个管理者的身份,上层提供调用接口,下层通过调用接口中的具体实现操控硬件,此处 为了理解硬件也算文件,就需要研究下层中接口的实现

此处不讨论接口中具体的代码实现,只讨论这整个过程是如何形成的

据冯诺依曼体系结构,除了内存、CPU以外,其他设备均称为外设,也称为输入输出设备,而这些设备在接入计算机时,需要在计算机中安装驱动,而安装驱动的本质就是为了将对应的硬件信息加载到属于硬件的信息表中,而操作系统为了管理这些表,就需要创建一个结构体,这一个过程符合「先描述,再组织」的「描述」,此处的每一个结构体都是通过双向链表进行连接,这一个过程符合「先描述,再组织」的「组织」。有了硬件信息的结构体和对应的数据结构,操作系统就可以开始通过管理这一个硬件信息数据结构来管理硬件,这一个过程就可以理解为实现「硬件即文件」的初步过程

但是上面的过程只是完成了硬件信息之间的联系,这些联系只能做到简单的增删查改,操作系统不可能 一直停留在添加设备和删除设备的行为中,这也没有意义。上文提到这些硬件本身都属于输入输出设 备,最基本的行为就是输入和输出,即I/O行为,所以每一个硬件都有属于自己的一套I/O行为方法,尽管 有的只有输出,有的只有输入,而因为方法的实现不同,导致操作硬件的方法就不同,在C语言中,不允 许在结构体中定义方法(也称函数),所以每一个设备的方法都独立于设备结构外,此时如果进程需要 调用就会显得不方便(调用顺序: task_struct -> file_struct -> file 访问到指定硬件信息,单 独调用指定方法传参),为了简化这一步骤,考虑将指定方法的地址作为 file 结构的成员(即结构体中 存储函数指针),此时进程调用即可通过 file 结构调用指定文件,而不需要再访问指定的硬件结构以及 单独调用指定的方法,所以此时每一个结构体的属性和方法就可以通过 file 结构来进行管理和访问,最 终做到了「硬件即文件」

在上面的过程中,使用 file 结构描述所有文件,包括硬件视为文件在内的系统称为Linux下的虚拟文件 系统(Virtual File System,简称VFS),有了前面的介绍,现在基本介绍一下虚拟文件系统的作用:虚 拟文件系统是操作系统的文件系统虚拟层,在其下是实体的文件系统。虚拟文件系统的主要作用在于让 上层的软件,能够用单一的方式,来跟底层不同的文件系统沟通。在操作系统与之下的各种文件系统之 间,虚拟文件系统提供了标准的操作接口,让操作系统能够很快的支持新的文件系统

简单理解这个作用就是让每一个进程访问每一个文件都认为是同一种文件,而不是每一个文件都是独立 的个体

补充:在上面的描述中提到一个点:file结构体中保存了函数指针和文件属性字段,而其他文件只需要 实现自己对应的函数即可,这个过程非常像C++面向对象三大特性中的一大特性:多态,多态的基本形 式为父类提供方法名但不实现,由具体的子类去实现,所以上面C语言中的思路也可以理解为是C语言中 实现多态的一种方式

Linux 2.6.0内核源代码中的file_operations结构体如下:

struct file_operations {
    struct module *owner;
    loff_t (*llseek) (struct file *, loff_t, int);
    ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
    ssize_t (*aio_read) (struct kiocb *, char __user *, size_t, loff_t);
    ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
    ssize_t (*aio_write) (struct kiocb *, const char __user *, size_t, loff_t);
    int (*readdir) (struct file *, void *, filldir_t);
    unsigned int (*poll) (struct file *, struct poll_table_struct *);
    int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
    int (*mmap) (struct file *, struct vm_area_struct *);
    int (*open) (struct inode *, struct file *);
    int (*flush) (struct file *);
    int (*release) (struct inode *, struct file *);
    int (*fsync) (struct file *, struct dentry *, int datasync);
    int (*aio_fsync) (struct kiocb *, int datasync);
    int (*fasync) (int, struct file *, int);
    int (*lock) (struct file *, int, struct file_lock *);
    ssize_t (*readv) (struct file *, const struct iovec *, unsigned long, loff_t *);
    ssize_t (*writev) (struct file *, const struct iovec *, unsigned long, loff_t *);
    ssize_t (*sendfile) (struct file *, loff_t *, size_t, read_actor_t, void __user *);
    ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
    unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
};

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

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

相关文章

如何在 MacOS 上安装 Flutter ?

Flutter 是 Google 开发的一个功能强大的框架&#xff0c;它允许开发人员从单个代码库构建高质量的、本机编译的移动、web 和桌面应用程序。如果你是初次接触 Flutter&#xff0c;并希望在你的 macOS 系统上安装它&#xff0c;本指南将引导你一步一步地完成这个过程。 Step 1:…

【2025最新计算机毕业设计】基于SpringBoot+Vue社区医院挂号健康服务平台【提供源码+答辩PPT+文档+项目部署】

作者简介&#xff1a;✌CSDN新星计划导师、Java领域优质创作者、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战,高校老师/讲师/同行前辈交流。✌ 主要内容&#xff1a;&#x1f31f;Java项目、Python项目、前端项目、PHP、ASP.NET、人工智能…

Docker安装MySQL5.5版本数据库(图文教程)

本章教程,介绍如何使用Docker安装MySQL低版本5.5版本的数据库。 一、拉取镜像 docker pull mysql:5.5二、启动容器 docker run -d --name mysql5.5 --restart=always

可视化建模与UML《部署图实验报告》

一、实验目的&#xff1a; 1、熟悉部署图的基本功能和使用方法。 2、掌握使用建模工具软件绘制部署图的方法 二、实验环境&#xff1a; window11 EA15 三、实验内容&#xff1a; 根据以下的描述&#xff0c;绘制部署图。 网上选课系统在服务器端使用了两台主机&#xff0c;一…

Python的3D可视化库【vedo】2-3 (plotter模块) 增删物体、控制相机

文章目录 4 Plotter类的方法4.3 渲染器内的物体操作4.3.1 添加物体4.3.2 移除物体4.3.3 渲染器的内容列表 4.4 相机控制4.4.1 访问相机对象4.4.2 重置相机状态4.4.3 移动相机位置4.4.4 改变相机焦点4.4.5 改变相机朝向的平面4.4.5 旋转相机4.4.6 对齐相机的上朝向4.4.7 缩放 pl…

07篇(附)--仿射变换矩阵

此篇献给某些 头铁 的小只因们&#xff0c;认真钻研下面的数学式吧 原理示例 首先我们以最简单的一个点的旋转为例子&#xff0c;且以最简单的情况举例&#xff0c;令旋转中心为坐标系中心O&#xff08;0&#xff0c;0&#xff09;&#xff0c;假设有一点P0(x0,y0)&#xff0…

Unity屏幕截图、区域截图、读取图片、WebGL长截屏并下载到本地jpg

Unity屏幕截图、区域截图、读取图片、WebGL长截屏并下载到本地jpg 一、全屏截图并保存到StreamingAssets路径下 Texture2D screenShot;//保存截取的纹理public Image image; //显示截屏的Imagepublic void Jietu(){StartCoroutine(ScrrenCapture(new Rect(0, 0, Screen.width…

【2025最新计算机毕业设计】基于SprintBoot+Vue乡村振兴民宿管理系统【提供源码+答辩PPT+文档+项目部署】

作者简介&#xff1a;✌CSDN新星计划导师、Java领域优质创作者、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战,高校老师/讲师/同行前辈交流。✌ 主要内容&#xff1a;&#x1f31f;Java项目、Python项目、前端项目、PHP、ASP.NET、人工智能…

在Docker中运行MySQL的思考:挑战与解决方案

引言 在云计算和容器化技术日益普及的今天&#xff0c;Docker作为一种轻量级的容器化平台&#xff0c;已经成为开发和部署应用的首选工具之一。其提供的便携性、可扩展性和环境一致性对于无状态微服务来说无疑是巨大的福音。然而&#xff0c;并非所有应用都适合在Docker容器中…

【Linux网络】网络基础:传输层TCP协议(二)

&#x1f4dd;个人主页&#x1f339;&#xff1a;Eternity._ ⏩收录专栏⏪&#xff1a;Linux “ 登神长阶 ” &#x1f339;&#x1f339;期待您的关注 &#x1f339;&#x1f339; ❀ 传输层UDP/TCP协议 确认应答机制超时重传机制连接管理机制理解 TIME_WAIT 状态 滑动窗口流量…

virtualbox 搭建ubuntu

环境&#xff1a;VirtualBox-6.1.32 1、下载安装virtualbox 略 2、新建ubuntu 3、配置ubuntu 选择虚拟盘 4、安装ubuntu 5、安装ssh sudo apt install openssh-server openssh-client 查看ip 6、安装samba sudo apt install samba 查看ssh启动状态 sudo systemctl stat…

智能人体安全防护:3D 视觉技术原理、系统架构与代码实现剖析

随着工业化程度的提高&#xff0c;生产安全已成为企业关注的重点。尤其是在一些存在禁区的工业厂区和车间&#xff0c;人员误入或违规进入将带来严重的安全隐患。为了解决这一问题&#xff0c;迈尔微视推出了智能人体安全检测解决方案&#xff0c;为企业提供全方位的人员安全监…

Javaweb web后端maven介绍作用安装

自动导入到这个项目 src是源代码 main主程序&#xff0c;核心代码 java是Java源代码 resources是项目配置文件 test测试相关的 maven概述 介绍 依赖在本地仓库查找&#xff0c;如果本地仓库有&#xff0c;用本地仓库的依赖&#xff0c;本地没有&#xff0c;连接中央仓库&…

独家原创 | CEEMDAN-CNN-GRU-GlobalAttention + XGBoost组合预测

往期精彩内容&#xff1a; 时序预测&#xff1a;LSTM、ARIMA、Holt-Winters、SARIMA模型的分析与比较 全是干货 | 数据集、学习资料、建模资源分享&#xff01; EMD变体分解效果最好算法——CEEMDAN&#xff08;五&#xff09;-CSDN博客 拒绝信息泄露&#xff01;VMD滚动分…

网络基础概念

协议 协议在我的理解看来其实就是为了让全部计算机做通信而设计出来的一种约定 计算机之间的传输媒介是光信号和电信号. 通过 "频率" 和 "强弱" 来表示 0 和 1 这样的信息. 要想传递各种不同的信息, 就需要约定好双方的数据格式 而制定协议这件事情并不是…

向量数据库Faiss C++

目录 1. Faiss简介2. FAISS 的主要特点2.1 高效性2.2 支持多种索引类型2.3 灵活性2.4 GPU 加速2.5 易于集成 3. 应用场景4. 安装4.1 安装依赖4.2 编译源码4.2.1 下载Faiss源码4.2.2 编译 5. Demo5.1 代码5.2 编译5.3 运行 1. Faiss简介 FAISS&#xff08;Facebook AI Similari…

群控系统服务端开发模式-应用开发-获取登录者今天操作日志

一、后端api开放路由 在根目录下route文件夹下app.php文件中&#xff0c;在perimission的group中添加如下代码&#xff1a; Route::get(member/personal_log,permission.Member/personalLog);// 获取个人信息操作接口 二、后端api添加方法 在根目录下app文件夹下controller文…

淘宝/天猫获得淘宝商品详情高级版 API 接口获取

要获取淘宝/天猫商品详情高级版API接口&#xff0c;您可以按照以下步骤操作&#xff1a; 注册淘宝开放平台账号&#xff1a; 访问淘宝开放平台官网&#xff0c;点击“开发者中心”&#xff0c;使用淘宝账号登录或注册新账号。这是获取API权限和密钥的第一步。 创建应用并获取AP…

腾讯云系统盘扩容

在腾讯云申请空间后&#xff0c;只要执行三行命令 云硬盘 在线扩展系统盘分区及文件系统-操作指南-文档中心-腾讯云 安装工具 yum install -y cloud-utils-growpart 给/eav/vda1扩分区 LC_ALLen_US.UTF-8 growpart /dev/vda 1 挂载扩容 ext4 文件系统 resize2fs /dev/vda1 …

数据结构 ——二叉树转广义表

数据结构 ——二叉树转广义表 1、树转广义表 如下一棵树&#xff0c;转换为广义表 root(c(a()(b()()))(e(d()())(f()(j(h()())())))) (根&#xff08;左子树&#xff09;&#xff08;右子树&#xff09;) 代码实现 #include<stdio.h> #include<stdlib.h>//保存…