Linux 文件系统:文件描述符、管理文件

news2024/9/21 16:44:19

目录

一、三个标注输入输出流

二、文件描述符fd

1、通过C语言管理文件—理解文件描述符fd

2、文件描述符实现原理

3、文件描述符0、1、2

4、总结

三、如何管理文件

1、打开文件的过程

2、内核空间的结构

struct task_struct(PCB)

struct files_struct和struct file *fd_array[]

struct file

3、深入到内核空间的操作 

fopen()的操作流程:

fwrite()操作流程


一、三个标注输入输出流

在Linux系统中,存在一个核心概念:“一切皆文件”。这意味着系统中的几乎所有东西,包括硬件设备如键盘和显示器,都被抽象为文件。这种设计使得与这些设备的交互变得统一和简化,因为你可以使用标准的文件操作API来与它们交互。

尽管如此,我们通常不会直接“打开”键盘或显示器文件来进行读写操作。相反,C和C++程序通常通过标准输入输出流来与这些设备交互。这是因为C/C++的标准库(如stdio.h)为我们提供了一组抽象的输入输出功能,这些功能背后默认与键盘和显示器等设备的文件描述符相连接。

当你启动一个C或C++程序时,运行时环境(如操作系统的shell)会自动为程序打开三个基本的文件流:

  • 标准输入(stdin):通常与键盘关联,用于读取输入。在程序中,它被表示为FILE* stdin;
  • 标准输出(stdout):通常与显示器关联,用于输出信息。在程序中,它被表示为FILE* stdout;
  • 标准错误(stderr):也通常与显示器关联,但用于输出错误信息。在程序中,它被表示为FILE* stderr;

这三个流在程序开始执行时就已经打开并可用,因此可以直接使用如printfscanffgets等函数进行输出和输入操作,而无需手动打开任何文件。这些函数内部会处理与标准输入输出流相关的所有细节,使得与用户的交互变得简单直接。

简而言之,虽然Linux下一切皆文件,包括键盘和显示器,但是在C/C++程序中,我们通过标准的输入输出流(stdin、stdout、stderr)来与这些设备进行交互,而无需直接打开或操作它们的文件描述符。这些流在程序启动时由运行时环境自动为我们打开和配置。

二、文件描述符fd

1、通过C语言管理文件—理解文件描述符fd

在C语言的世界里,FILE 是一个关键的概念,用于表示文件流。它实际上是一个结构体,由C标准库提供,内含多种成员,旨在抽象和管理文件操作的复杂性。这个结构体封装了文件的各种信息,如缓冲状态、当前读写位置等,让开发者能够通过一系列标准库函数,如 fopenfwritefread 等,来方便地进行文件操作。

        然而,当我们深入到操作系统的层面,尤其是在UNIX或类UNIX系统中,会发现操作系统本身并不直接认识 FILE 结构体。对于操作系统而言,文件是通过文件描述符(File Descriptor, 简称fd)来识别和管理的。文件描述符是一个非常底层的概念,它是一个整数值,代表了进程中打开文件的唯一标识。

        因此,虽然在使用C标准库进行文件操作时我们操作的是 FILE 类型的指针,底层实现这些功能的时候,C库函数实际上会转换成操作系统理解的文件描述符。这意味着,尽管我们在编程时与 FILE 打交道,C标准库在背后会处理与文件描述符相关的所有细节,确保我们的文件操作最终能够被操作系统正确执行。这一层抽象既隐藏了底层的复杂性,也提供了更丰富、更易用的接口给程序员。

2、文件描述符实现原理

通过对open函数的学习,我们知道了文件描述符就是一个小整数,其内部实现是通过位图的原理,具体实现方式如下:
#include <stdio.h>

// 定义标志位,用int中的不重复的一个bit,就可以标识一种状态
#define ONE   0x1    //0000 0001
#define TWO   0x2    //0000 0010
#define THREE 0x4    //0000 0100

// 显示函数,根据标志位输出不同的消息
void show(int flags) {
    if (flags & ONE)  
        printf("你好,第一种状态\n");
    if (flags & TWO)
        printf("你好,第二种状态\n");
    if (flags & THREE)
        printf("你好,第三种状态\n");
}

int main() {
    // 分别显示不同的状态
    show(ONE);
    show(TWO);
    show(ONE | TWO); // 使用按位或运算符组合标志位
    show(ONE | TWO | THREE);//0000 0001 | 0000 0010=0000 0011
    show(ONE | THREE);
    return 0;
}

[hbr@VM-16-9-centos exercise_func]$ ./mytest 
你好,第一种状态
-----------------------------------------
你好,第二种状态
-----------------------------------------
你好,第一种状态
你好,第二种状态
-----------------------------------------
你好,第一种状态
你好,第二种状态
你好,第三种状态
-----------------------------------------
你好,第一种状态
你好,第三种状态

3、文件描述符0、1、2

在Linux进程中,文件描述符0、1、和2分别用于标准输入(stdin)、标准输出(stdout)、和标准错误(stderr)的缺省打开。这三个文件描述符为进程通信与数据输入输出提供了基础。

  • 当你从键盘输入时,默认情况下,这些输入数据通过文件描述符0(标准输入)进入程序;
  • 当程序需要输出信息到屏幕时,它会使用文件描述符1(标准输出)和文件描述符2(标准错误),其中标准输出用于常规信息,标准错误专用于输出错误信息。

从文件描述符3开始,是进程打开或创建的其他文件和资源的描述符。

  • 当一个进程通过如open系统调用打开或创建新文件时,分配给该文件的文件描述符将是当前未被使用的最小的正整数文件描述符。
  • 这意味着,如果进程没有打开除标准输入、输出和错误外的其他文件,那么新打开的文件将使用文件描述符3。

通过下面程序就明白了:

[hbr@VM-16-9-centos exercise_func]$ cat testC.c 
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main() 
{
    umask(0);
    int fd1 = open("log1.txt", O_WRONLY|O_CREAT|O_APPEND,0666); 
    printf("open success, fd1: %d\n", fd1);
    int fd2 = open("log2.txt", O_WRONLY|O_CREAT|O_APPEND,0666); 
    printf("open success, fd2: %d\n", fd2);
    int fd3 = open("log3.txt", O_WRONLY|O_CREAT|O_APPEND,0666); 
    printf("open success, fd3: %d\n", fd3);
    int fd4 = open("log4.txt", O_WRONLY|O_CREAT|O_APPEND,0666); 
    printf("open success, fd4: %d\n", fd4);

    close(fd1);
    close(fd2);
    close(fd3);
    close(fd4);
    return 0;
}
[hbr@VM-16-9-centos exercise_func]$ ll
total 40
-rw-rw-r-- 1 hbr hbr   72 Mar 18 21:19 makefile
-rwxrwxr-x 1 hbr hbr 8664 Mar 18 23:20 mytest
-rw-rw-r-- 1 hbr hbr  954 Mar 18 23:29 testC.c
[hbr@VM-16-9-centos exercise_func]$ make
gcc -std=c99 -o mytest testC.c
[hbr@VM-16-9-centos exercise_func]$ ./mytest 
open success, fd1: 3
open success, fd2: 4
open success, fd3: 5
open success, fd4: 6
[hbr@VM-16-9-centos exercise_func]$ ll
total 40
-rw-rw-rw- 1 hbr hbr    0 Mar 18 23:30 log1.txt
-rw-rw-rw- 1 hbr hbr    0 Mar 18 23:30 log2.txt
-rw-rw-rw- 1 hbr hbr    0 Mar 18 23:30 log3.txt
-rw-rw-rw- 1 hbr hbr    0 Mar 18 23:30 log4.txt
-rw-rw-r-- 1 hbr hbr   72 Mar 18 21:19 makefile
-rwxrwxr-x 1 hbr hbr 8512 Mar 18 23:30 mytest
-rw-rw-r-- 1 hbr hbr  954 Mar 18 23:29 testC.c

这个编号系统继续下去,对于每一个新打开的文件或资源(如网络套接字),内核都会分配一个唯一的、递增的文件描述符。这使得进程可以同时管理多个输入输出流,包括文件读写、网络通信等。

现在知道,文件描述符就是从0开始的小整数。
  • 当我们打开文件时,操作系统在内存中要创建相应的数据结构来描述目标文件。于是就有了file结构体。表示一个已经打开的文件对象。
  • 而进程执行open系统调用,所以必须让进程和文件关联起来。
  • 每个进程都有一个指针*files, 指向一张表files_struct,该表最重要的部分就是包涵一个指针数组,每个元素都是一个指向打开文件的指针!
  • 所以,本质上,文件描述符就是该数组的下标。所以,只要拿着文件描述符,就可以找到对应的文件。

4、总结

在Linux系统中,文件标识符(File Identifier)通常指的是文件描述符(File Descriptor)。文件描述符是一个非负整数,用于唯一标识一个已打开的文件或I/O流。

  1. 标识打开文件:文件描述符是操作系统用来标识已打开文件的机制。每个打开的文件都会有一个对应的文件描述符。

  2. 整数值:文件描述符是一个非负整数,通常从0开始递增。标准输入、标准输出和标准错误的文件描述符分别是0、1和2,从文件描述符3开始,是进程打开或创建的其他文件和资源的描述符。

  3. 系统调用参数:文件描述符通常作为参数传递给系统调用,比如readwriteclose等,以指定要操作的文件。

  4. 资源管理:操作系统会维护一个文件描述符表,用于跟踪每个进程打开的文件及其对应的文件描述符。这个表中记录了文件描述符和文件之间的映射关系。

  5. 文件操作:通过文件描述符,程序可以进行文件的读取、写入和其他操作。文件描述符是进行文件 I/O 操作的关键。

  6. 标准文件描述符:在Linux系统中,通常有三个标准文件描述符:0(标准输入)、1(标准输出)和2(标准错误),它们分别对应键盘输入、终端输出和错误信息输出。

三、如何管理文件

一个进程不仅可以打开多个文件,而且这种情况非常普遍,形成了一对多(1:n)的关系。所以,在操作系统的内部,为了有效地管理众多被打开的文件,确实需要对这些文件进行适当的组织和管理。

操作系统会为每一个被打开的文件创建一个结构体(通常称为 struct file 或类似的名称),该结构体包含了关于这个文件的几乎所有信息,如文件的属性、位置指针、读写权限等。如果存在大量的被打开的文件,操作系统会通过数据结构,如双链表,来组织这些 struct file 的实例,以便高效管理和访问。

 文件描述符fd在内核中的表现,可以被理解为指向这些 struct file 实例的指针数组的下标。

1、打开文件的过程

  • 当一个进程请求打开一个文件时,操作系统会首先在内核中创建一个对应的 struct file 对象。
  • 接着,它会在文件描述符表(这是一个每个进程都有的、指向 struct file 实例的指针数组)中寻找一个未被使用的条目,并将新创建的 struct file 对象的引用存放在那里。最后,操作系统将这个条目的索引(即文件描述符)返回给进程。
  • 因此,当进程需要进行文件操作时,它会提供文件描述符作为参数。操作系统通过这个文件描述符,查找进程的文件描述符表,从而找到对应的 struct file 对象,进而进行具体的文件操作。这种机制既简化了文件操作的接口,也保证了操作的安全性和效率。

2、内核空间的结构

struct task_struct(PCB)

  • 每个运行中的进程在内核中都有一个struct task_struct实例,其中包含了进程的所有信息,包括它的文件描述符表,通过files指针指向struct files_struct

struct files_structstruct file *fd_array[]

  • struct files_struct维护了一个文件描述符表fd_array[],这个表是一个指针数组,每个指针指向一个struct file实例。文件描述符(fd)实质上是这个数组的索引。

struct files_struct是Linux内核中的一个结构体,它的主要作用是管理和跟踪一个进程打开的所有文件描述符。在Linux系统中,当进程打开一个文件时,内核会为该文件分配一个文件描述符(fd),这是一个非负整数,用作索引来访问进程打开的文件。文件描述符为进程与打开的文件之间的交互提供了一个简单的抽象。

  • 具体来说,struct files_struct包含了以下关键信息:
  • count: 一个引用计数,表示有多少个地方引用到这个files_struct。这是用于内存管理和确保结构体在不再被需要时可以被正确地释放。
  • fdt: 指向一个fdtable结构的指针,该结构实际上保存了文件描述符的数组(fd_array)以及与之相关的一些其他数据,如文件描述符的最大数量等。
  • fd_array: 通常作为fdtable的一部分,这是一个指针数组,每个指针指向一个struct file结构体实例。每个struct file实例代表一个打开的文件,包含了文件的当前状态、位置偏移量、以及文件操作的方法等信息。
  • 文件描述符的分配和回收机制files_struct还管理着文件描述符的分配和回收,确保每次打开文件时都能分配一个唯一的最小可用文件描述符,并在文件关闭时回收该描述符。
  • 通过管理每个进程的文件描述符表,struct files_struct为进程提供了对打开文件的有效访问和控制,使得进程可以执行读写、查询状态以及执行其他文件操作。

struct file

  • struct file代表一个打开的文件的所有信息,包括文件的状态、当前偏移量、与文件相关的操作函数等。它是实际执行读写操作的基础。

3、深入到内核空间的操作 

FILE *stdout = fopen("显示器",“w");-> open->1
stdout -> FILE* -> FILE->fileno(1)

  • FILE *stdout = fopen("显示器", "w");

    • 用户程序请求打开"显示器"(在实际应用中,stdout通常预定义且指向标准输出)进行写操作。fopen函数内部调用open系统调用,并将返回的文件描述符(fd)封装在一个FILE结构体中。这个结构体提供了一个高级接口来进行后续的文件I/O操作。

fopen()的操作流程:

fopen->open->检查并分配fd->struct file->在struct file *fd_array[fd]指向struct file->fopen从open获得fd->创建FILE*

  1. 接收参数fopen()函数被调用时,接收两个参数:文件路径(path)和模式(mode)。模式指定了文件的访问类型(如读取、写入、追加等)。

  2. 高级抽象:通过FILE *指针,fopen()为程序员提供了一个高级的文件操作抽象。FILE *封装了文件描述符(fd)以及其他进行文件I/O所需的信息,比如缓冲区的地址、缓冲区大小、文件的当前位置指针等。

  3. 系统调用open()获取fdfopen()内部会调用系统调用open(),向操作系统请求打开指定路径的文件。

    1. 内核处理:操作系统内核接收到open系统调用后,会执行以下操作:

      • 内核会检查进程的权限以确定是否允许打开指定文件。
      • 如果权限检查通过,内核会为该文件分配一个文件描述符。
  4. 创建struct file结构体:一旦open系统调用被执行,内核首先会进行权限检查、解析路径等操作。如果所有检查都通过,内核会创建一个struct file实体来代表这个新打开的文件。

  5. 进程打开的文件会被加入到文件描述符表:open函数返回文件描述符fd之后,进程打开的文件会被加入到文件描述符表struct file *fd_array[]中。这意味着文件描述符表会在文件被成功打开后更新,以便进程可以通过文件描述符来访问该文件。

    1. 文件描述符表:在task_struct中,有一个指向files_struct的指针,files_struct维护着进程打开的所有文件的信息,包括文件描述符表fd array[]。由此获取到文件描述符(fd),并将其作为索引,访问到对应的文件信息。

  6. 创建FILE结构体实例

    1. 一旦struct file实体创建完成,并且open系统调用成功,内核会将相应的文件描述符(fd)返回给用户空间的调用者。这个文件描述符实际上是struct file实体在进程文件描述符表中的索引。

    2. 一旦fopenopen系统调用获取到文件描述符(fd),它会在用户空间分配并初始化一个FILE结构体实体,这个实体封装了文件描述符和其他高级I/O操作所需的信息,如缓冲区等。
    3. fopen之后返回的是一个指向FILE结构体的指针,供用户程序进行后续的文件操作。
  • 当一个进程调用 open() 等系统调用来打开文件时,实际上并不需要直接访问该进程的 task_struct 结构体。文件的打开操作是基于进程的文件描述符表进行的,这个表存储了进程打开的文件以及它们对应的文件描述符。
  • 文件描述符表是由进程的 files_struct 结构体间接引用的,而 files_struct 结构体是存储在进程的 task_struct 结构体中的。因此,虽然文件的打开操作涉及到文件描述符表,但并不需要直接访问进程的 task_struct 结构体,因为文件描述符表是通过 task_struct 间接引用的。这种间接引用的设计使得操作系统能够有效地管理进程的文件描述符和文件操作,同时保持进程信息的封装和隔离。

fwrite()操作流程

fwrite()-> FILE* -> fd -> write -> write(fd,...) -> 自己执行操作系统内部的write方法 ->能找到进程的task struct->*fs -> files struct->fd arrayl]->fd array[fd]->struct file->内存文件被找到了! ->进行写入操作。

  1. 首先,fwrite()函数接收一个FILE*类型的指针,这是C语言标准库提供的文件操作的高级抽象。通过FILE*指针获得背后关联着一个文件描述符(fd),它是一个低级的概念,直接与操作系统的文件系统接口相连。
  2. fwrite()被调用时,它最终会通过一系列转换和底层调用,调用到操作系统的write()函数,具体形式为write(fd, ...)。这个write()函数是系统调用,直接与内核交互,执行具体的写入操作。
  3. 访问task_struct:每个进程在操作系统内部都有一个代表它的task_struct结构体。当进程执行write()调用时,系统已经通过当前的执行上下文(比如CPU的当前执行线程关联的进程)直接访问到了该进程的task_struct。这不是通过文件描述符完成的,而是基于当前正在执行的进程上下文。
  4. task_struct是Linux内核中的进程控制块(PCB),包含了进程的所有信息。在task_struct中,有一个指向files_struct的指针,这个files_struct维护着进程打开的所有文件的信息,包括一个文件描述符表fd array[]
  5. fd array[]中,通过文件描述符fd作为索引,可以找到对应的struct file实例。struct file包含了文件的详细信息,包括文件的当前状态、位置偏移量以及如何操作这个文件的方法等。
  6. 找到了struct file之后,操作系统就能够确定具体要操作的内存中的文件。随后,它执行写入操作,将数据从用户空间传输到内核空间,最终写入到文件中。

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

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

相关文章

html5播放flv视频

参考&#xff1a;flv-h265 - npmHTML5 FLV Player. Latest version: 1.7.0, last published: 6 months ago. Start using flv-h265 in your project by running npm i flv-h265. There are no other projects in the npm registry using flv-h265.https://www.npmjs.com/packag…

java类的定义及使用

1、类的定义 &#xff08;1&#xff09;类的重要性&#xff1a;是Java程序的基本组成单位&#xff1b; &#xff08;2&#xff09;类是什么&#xff1a;是对现实生活中一类具有共同属性和行为的事物的抽象&#xff0c;确定对象将会拥有的属性和行为&#xff1b; &#xff08…

卷积篇 | YOLOv8改进之C2f模块融合SCConv | 即插即用的空间和通道维度重构卷积

前言:Hello大家好,我是小哥谈。SCConv是一种用于减少特征冗余的卷积神经网络模块。相对于其他流行的SOTA方法,SCConv可以以更低的计算成本获得更高的准确率。它通过在空间和通道维度上进行重构,从而减少了特征图中的冗余信息。这种模块的设计可以提高卷积神经网络的性能。本…

AI时代,Matter如何融入与服务中国智能家居市场,助力中国企业出海?

随着智能家居产业的飞速发展&#xff0c;丰富多样的智能家居产品为消费者带来了便利的同时&#xff0c;因为不同品牌、不同产品之间的协议与标准不统一&#xff0c;导致消费者体验产生割裂&#xff0c;本来想买个“智能”家居&#xff0c;结果买了个“智障”家居&#xff0c;这…

C++开发基础——类对象与构造析构

一、基础概念 类&#xff1a;用户自定义的数据类型。 对象&#xff1a;类类型的变量&#xff0c;类的实例。 类的成员&#xff1a;成员变量和成员函数。 成员变量&#xff1a;类中定义的变量。 成员函数&#xff1a;类中定义的函数。 定义类的代码样例&#xff1a; class…

社区生活超市管理系统|基于JSP技术+ Mysql+Java+ Tomcat的社区生活超市管理系统设计与实现(可运行源码+数据库+设计文档)

推荐阅读100套最新项目 最新ssmjava项目文档视频演示可运行源码分享 最新jspjava项目文档视频演示可运行源码分享 最新Spring Boot项目文档视频演示可运行源码分享 2024年56套包含java&#xff0c;ssm&#xff0c;springboot的平台设计与实现项目系统开发资源&#xff08;可…

【Unity动画】Unity如何导入序列帧动画(GIF)

Unity 不支持GIF动画的直接播放&#xff0c;我们需要使用序列帧的方式 01准备好序列帧 02全部拖到Unity 仓库文件夹中 03全选修改成精灵模式Sprite 2D ,根据需要修改尺寸&#xff0c;点击Apply 04 创建一个空物体 拖动序列上去 然后全选所有序列帧&#xff0c;拖到这个空物体…

python异常:pythonIOError异常python打开文件异常

1.python读取不存在的文件时&#xff0c;抛出异常 通过 open()方法以读“r”的方式打开一个 abc.txt 的文件&#xff08;该文件不存在&#xff09;&#xff0c;执行 open()打开一个不存在的文件时会抛 IOError 异常&#xff0c;通过 Python 所提供的 try...except...语句来接收…

Java基础经典10道题

目录 for循环的嵌套 题目一: 求101到200之间的素数的个数,并打印 代码分析: 注意点: 题目二:开发验证码 代码分析: 题目三:数组元素的复制 代码分析: 题目四:评委打分 健壮版代码: 代码分析:看源码 注意点: 题目五:数字加密 优化版代码: 代码分析: 题目六:数字…

HandyControl PropertyGrid及自定义编辑器

前提条件 项目引入对应HandyControl对应版本包。 使用案例 UI部分 <Window xmlns:hc"https://handyorg.github.io/handycontrol"><hc:TabControl><hc:TabItem Header"默认样式"><hc:PropertyGrid Width"380" SelectedO…

[RCTF2015]EasySQL ---不会编程的崽

今天也是sql注入的新类型---二次注入。不得不说花样真的多哦。 既然真的是sql注入了。那就不测试其他地方了。现在注册进去看一下界面 单纯的回显了名字。源代码里发现user.php。 可以修改密码&#xff1f;二次注入应该就在用户名这里了。因为修改密码时&#xff0c;用户名会被…

学习笔记Day11:初探Linux

Linux系统初探 Linux系统简介 发行版本Ubuntu/centOS&#xff0c;逻辑一样&#xff0c;都可以用。 服务器 本质是一台远程电脑&#xff0c;大多数服务器是Linux系统&#xff0c;通常使用命令行远程访问而不是桌面操作。LInux服务器允许多用户同时访问。NGS组学测序数据上游…

硬盘哨兵Hard Disk Sentinel Pro V6.20.0.0 便携版

Hard Disk Sentinel 是一款功能强大的硬盘监控和分析软件&#xff0c;专为 Windows 用户设计。它可以实时监测硬盘驱动器&#xff08;HDD&#xff09;、固态硬盘&#xff08;SSD&#xff09;、混合硬盘&#xff08;SSHD&#xff09;、NVMe SSD、RAID 数组和外部 RAID 盒子的健康…

pdf文件属性的删除

pdf文件属性的删除 投标过程中需要处理文件属性&#xff0c;特别是word文件属性以及pdf文件的处理 这里讲解pdf文件属性的处理 word处理在我的另外一个博客中&#xff0c;word文件属性的处理 https://ht666666.blog.csdn.net/article/details/134102504 一般用 adobe acroba…

MySQL—数据库导入篇

什么是数据库&#xff1f; 数据库是干啥的&#xff1f; 数据库&#xff08;Database&#xff09;是按照数据结构来组织、存储和管理数据的仓库。 MySQL属于哪一类数据库&#xff1f; MySQL是一种关系型数据库。所谓的关系型数据库&#xff0c;是建立在关系模型基础上的数据库&a…

LabVIEW飞行器螺旋桨性能测试与数据监控

LabVIEW飞行器螺旋桨性能测试与数据监控 开发LabVIEW的电动飞行器螺旋桨性能测试与数据监控系统&#xff0c;专门针对电动飞行器螺旋桨在运行过程中的性能测试和监控需求。通过采集转速、转矩、拉力和温度等关键参数&#xff0c;系统能够实时监测和分析螺旋桨的状态&#xff0…

深度学习_ResNet_5

ResNet学习目标 什么是ResNet为什么要引入ResNet&#xff1f;ResNet网络结构的特点利用ResNet完成图像分类 什么是ResNet&#xff1f; ResNet&#xff08;Residual Network&#xff09;是一种深度残差网络&#xff0c;由何凯明等人在2015年提出&#xff0c;是深度学习领域中一…

网络视频播放器|基于JSP技术+ Mysql+Java+ B/S结构的网络视频播放器设计与实现(可运行源码+数据库+设计文档)

推荐阅读100套最新项目 最新ssmjava项目文档视频演示可运行源码分享 最新jspjava项目文档视频演示可运行源码分享 最新Spring Boot项目文档视频演示可运行源码分享 2024年56套包含java&#xff0c;ssm&#xff0c;springboot的平台设计与实现项目系统开发资源&#xff08;可…

3D模型优化服务+三维可视化+数字孪生+元宇宙=眸瑞科技

眸瑞科技&#xff1a;老子云平台AMRT3D数字孪生引擎 老子云概述 老子云3D可视化快速开发平台&#xff0c;集云压缩、云烘焙、云存储云展示于一体&#xff0c;使3D模型资源自动输出至移动端PC端、Web端&#xff0c;能在多设备、全平台进行展示和交互&#xff0c;是全球领先、自…

MYSQL日志 redo_log更新流程 bin_log以及bin_log数据恢复

Redo_log写入策略 Redo log的Innodb_flush_log_at_trx_commit:: 这个参数有三个取值 取值为0&#xff1a;每次事务提交时&#xff0c;只是把redo_log留在 redo log buffer中&#xff0c;宕机会丢失数据&#xff1b; 取值为1&#xff08;默认值&#xff09;&#xff1a;每次事…