Linux 基础IO(上)--文件与文件描述符fd

 前言:

在生活里,我们常和各种文件打交道,像用 Word 写文档、用播放器看视频,这些操作背后都离不开文件的输入输出(I/O)。在 Linux 系统中,文件 I/O 操作更是复杂且关键。

接下来我们将深入探讨Linux 基础 IO,不仅包含了 C 语言文件 I/O 操作函数,如打开文件的fopen、读取文件的fread等常见接口,还详细讲解了系统文件 I/O 的函数和原理,以及文件描述符、重定向、缓冲区等重要概念(内容太多了,分成两篇博客介绍)。


目录

 前言:

一. 文件

       1.相关概念

            1.0 理解文件

           1.1文件组成:

            1.2文件路径:

            1.3文件访问:

             1.4进程与文件关系: 

​编辑

            1.5文件管理机制:

 2.系统调用接口

2.0 回顾C语言的函数接口

        2.01 从文件的打开到文件的关闭

       打开文件:fopen()

读取文件:fread()

文件修改:fwrite()

关闭文件:fclose()

       

         2.02 文件的错误处理

​编辑

2.03 默认的IO流 

 2.1. open,write,read,close函数:

           2.11 open函数

第一个参数pathname 

 第二个参数flags

第三个参数mode

open的返回值

2.2 write函数 

2.3 read函数

2.4close函数 

 三、文件描述符fd

3.1文件描述符的概念

3.2文件描述符与FILE*的区别

四.文件描述符fd分配规则

      4.1. 最小可用原则:

      4.2演示:


一. 文件

       1.相关概念

            1.0 理解文件

   狭义理解

  • 文件在磁盘里
  • 磁盘是永久性存储介质,因此文件在磁盘上的存储是永久性的(当然,时间久了肯定会有损害)
  • 磁盘是外设(即是输出设备也是输入设备,有文件从内存里读,就有文件向内存里写)
  • 对磁盘上所有文件的操作本质都是内存对外设的输入和输出,简称IO

   广义理解

  • 操作系统内一切皆文件
  • 操作系统为了方便管理各种各样的外设,选择将他们都看成文件便于管理。

           1.1文件组成:

                文件由属性和内容构成。

对于OKB的空文件是占用磁盘空间的,这是为啥呢???

大家可以想一想,我们平常在文件管理器上看到的KB大小,是不是指的文件大小,如果大小为0,为啥还会占用空间呢?很简单,磁盘当中存储的是我们文件的属性和内存,即使是空文件他还是要有文件本身的属性的。空文件在磁盘当中,存储的是文件的属性。

所以 文件=属性+内容


            1.2文件路径:

                (关于这一点我们在fopen那里会进一步讲解) 

                标定文件的唯一性需使用绝对路径(路径+文件名),未指定路径时默认当前目录。


            1.3文件访问:

                只有被打开的文件才能被进程访问,未被打开的文件存储在磁盘中。(后一部分   由文件系统管理,在下一篇博客中会专门讲解)


             1.4进程与文件关系: 

                        文件操作的本质是进程与被打开文件间的交互,由操作系统管理。多文件管理则是操作系统通过 `files_struct`统一 管理打开的文件,其中包含文件描述符表(fd数组),fd是数组索引。

就如图所示,每一个被打开的文件,操作系统都会分配一个file_struct的结构,管理并存储对应文件的属性与内容,而进程则是在PCB当中保存着一个可以指向被打开文件数组的指针,然后通过特定文件描述符访问或修改文件。


            1.5文件管理机制:

                        操作系统通过“先描述再组织”管理文件,内核中每个文件对应一个数据结构(`struct file`),包含文件属性和内容指针。

正如在1.4所说的,文件被操作系统用file_struct管理起来,如何管理不就是通过各种数据结构简单而高效的管理吗?这就是“再组织”的过程。通过对文件的结构的管理,不就实现了对文件的管理吗。


 2.系统调用接口

2.0 回顾C语言的函数接口

在C语言中,文件I/O操作主要是通过C语言的标准库提供的FILE *指针和一系列文件操作函数来实现的。这些函数为开发人员提供了更高层的文件操作接口,使得文件读写变得简单和方便。

        2.01 从文件的打开到文件的关闭
       打开文件:fopen()

  • filename:表示文件的路径,文件可以是相对路径或绝对路径。
  • mode:文件打开的模式,决定文件的读写方式。
  • 返回值:该函数成功返回打开文件的指针,失败着返回NULL。

"r"以只读模式打开文件,文件必须存在。
"w"

以写模式打开文件,若文件已存在,且文件有内容,则文件会被清空。

没有文件,则创建文件。

"a"以追加模式打开文件,若文件不存在则会创建文件。
"rb"以二进制模式只读打开文件,文件必须存在。
"wb"以二进制模式写入文件,若文件已存在则会被清空。

代码示例

  1 #include<stdio.h>2 #include<unistd.h>3 4 5 int main()6 {7   FILE* pf=fopen("text.txt","w");8   if(pf)9     printf("创建文件成功\n");                                                                     10   return 0;11 }
~

 结果

读取文件:fread()
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
  • ptr:指向内存的指针,用于存储读取的数据。
  • size:每个数据元素的大小(单位:字节)。
  • count:读取的元素个数。
  • stream:文件指针,指定从哪个文件读取数据。
  • 返回值:返回读取成功的字节个数

代码及结果

  1 #include<stdio.h>2 #include<unistd.h>3 4 5 int main()6 {7   FILE* pf=fopen("text.txt","r");8   if(!pf)9   {10     perror("open file failed:\n");11     return 99;12   }13     printf("打开文件成功\n");14     char buffer[100];15     size_t n=fread(buffer,sizeof(char),100,pf);16     if(n)                                                                                         17     {18       printf("读取成功\n");19       //之所以把数组的最后置成'\0',那是因为C语言的接口只能识别以’\0‘为结尾的字符串。20       buffer[n]='\0';21       printf("这是text.txt文件的内容:%s\n",buffer);22     }23   return 0;24 }

文件修改:fwrite()
size_t fwrite(const void *ptr, size_t size, size_t nmemb,FILE *stream);
  • ptr:指向内存中数据的指针。
  • size:每个数据元素的大小(单位:字节)。
  • count:写入的元素个数。
  • stream:文件指针,指定将数据写入哪个文件。 

    代码演示

      1 #include<stdio.h>2 #include<unistd.h>3 4 5 int main()6 {7 8   FILE* pf=fopen("text.txt","r");9   if(!pf)10   {11     perror("open file failed:\n");12     return 99;13   }14     printf("打开文件成功\n");15     char buffer[100]={"这是一段用于演示的代码,验证fwrite的功能\n"};16     size_t n=fwrite(buffer,sizeof(char),100,pf);17     if(n)18     {19       printf("读取成功\n");20       //之所以把数组的最后置成'\0',那是因为C语言的接口只能识别以’\0‘为结尾的字符串。21       buffer[n]='\0';22       printf("这是text.txt文件的内容:%s\n",buffer);23     }24   return 0;25 } 

    结果

    注:fwrite 函数本身既不是覆盖写也不是追加写,它的写入方式取决于文件的打开模式(是由'r'还是'w'决定的)。

    关闭文件:fclose()
    int fclose(FILE *fp);
    • fp:一个已经打开的文件指针 

    代码示例

    结果

           
             2.02 文件的错误处理

              在文件操作中,对于错误的处理是非常重要,C语言提供了两个函数来帮助开发者检测错误:ferror()feof()

    ferror()与feof()

     int feof(FILE *stream);int ferror(FILE *stream);
    
    • ferror(FILE *stream):判断是否发生了文件I/O错误。
    • 函数返回值:无错误出现时返回0;有错误出现时,返回一个非零值。
    • feof(FILE *stream):判断文件是否到达了末尾。
    • 函数返回值:如果没有到文件尾,返回0;到达文件尾,返回一个非零值。

    这两个错误处理的函数,主要是判断文件错误的类型。


    2.03 默认的IO流 

    都说Linux下一切皆文件,也就是说Linux下的任何东西都可以看作是文件(至少在操作系统看来),那么显示器和键盘当然也可以看作是文件。我们能看到显示器上的数据,是因为我们向“显示器文件”写入了数据,内存能获取到我们敲击键盘时对应的字符,是因为内存从“键盘文件”读取了数据。

    那么不有一个问题吗?文件的打开不是要进程主动打开使用吗?那为什么我们向“显示器文件”写入数据以及从“键盘文件”读取数据前,不需要进行打开“显示器文件”和“键盘文件”等相应操作?

    那自然是操作系统为我们打开了基础文件,任何进程在运行的时候都会默认打开三个输入输出流文件,即标准输入、标准输出以及标准错误,对应到C语言当中就是stdin、stdout以及stderr。

    查阅man手册

        extern FILE *stdin;extern FILE *stdout;extern FILE *stderr;
    

     当我们的C程序被运行起来时,操作系统就会默认使用C语言的相关接口将这三个输入输出流打开,之后我们才能调用类似于scanf和printf之类的函数向键盘和显示器进行相应的输入输出操作。

    当然在默认的情况下,stdout,stderr对应的外设都是显示器,stdin则是键盘。

    代码演示

    1 #include<unistd.h>2 #include<sys/types.h>3 #include<stdio.h>4 5 6 int main()7 {8   fclose(stdout);                                                                                                                                                                                            9   printf("这是一段用于演示,关闭标准输出流后,无法向显示器打印\n");10   return 0;11 }
    

    结果

     其实不止是C语言当中有标准输入流、标准输出流和标准错误流,C++当中也有对应的cin、cout和cerr,其他所有语言当中都有类似的概念。

    这也揭示了这种特性并不是某种语言所特有的,而是由操作系统所支持的。


     2.1. open,write,read,close函数:

            操作文件除了C语言接口、C++接口或是其他语言的接口外,操作系统也有一套系统接口来进行文件的访问。(各个语言对文件的访问,本质上都是对系统接口封装)。

    我们在Linux平台下运行C代码时,C库函数就是对Linux系统调用接口进行的封装,

    在Windows平台下运行C代码时,C库函数就是对Windows系统调用接口进行的封装,

    这样做使得语言有了跨平台性,也方便进行二次开发。

    (在不同的编译环境当中,C语言的库编写方式不同,因此在语言库的方面上保证C语言的可移植性)。

               2.11 open函数

                 man手册原型

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

            参数分析
             

    • pathname:要打开的文件的路径。
    • flags:文件打开模式,决定文件的访问方式。
    • mode:文件权限,通常在文件创建时使用。
    第一个参数pathname 

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

    还记得我们在“1.3文件路径”中所说的区别 

    什么是当前路径?
    我们知道,当fopen以写入的方式打开一个文件时,若该文件不存在,则会自动在当前路径创建该文件,那么这里所说的当前路径指的是什么呢?

    我们通过代码来验证一下

    代码

    1 #include<stdio.h>2 #include<unistd.h>3 4 5 int main()6 {7   FILE* pf=fopen("cwd.txt","w");                                                                  8   fclose(pf);9   return 0;10 }

    结果

    这是我们处于“cwd.exe”进程的相同的路径,结果与预想的差不多

    那是否意味着这里所说的“当前路径”是指“当前可执行程序所处的路径”呢?
    , 但如果我们处于与进程不同的路径下再次运行程序结果会如何呢??

    我们返回上级路径在测试一遍 

    这时我们可以发现,该可执行程序运行后并没有在FileIO目录下创建cwd.txt,而是在我们当前所处的路径下创建了cwd文本。

    为了解释这一现象,我们调出该进程的各项属性

    我们可以发现两个明显像是路径的变量,cwd就是进程运行时我们所处的路径,而exe就是该可执行程序的所处路径 

    总结: 实际上,我们这里所说的当前路径不是指进程运行时所处的路径,而是指该进程运行时我们所处的路径。


     第二个参数flags

    常见的flags参数包括:

    标志描述
    O_RDONLY以只读模式打开文件
    O_WRONLY以只写模式打开文件
    O_RDWR以读写模式打开文件
    O_CREAT文件不存在时创建文件
    O_TRUNC如果文件已存在,清空文件内容
    O_APPEND以追加模式打开文件

    在C语言中我们经常用一个整形来传递选项,但是如果如果选项较多时,就会造成空间的浪费,这里我们可以通过使用一个比特位表示一个标志位,这样一个int就可以同时传递至少32个标志位,此时的flag就可以看待成位图的数据类型。而上面的参数就是一个又一个不同位置的宏,代表的是不同的位。

    在打开文件的时候,利用“open”函数也可以达到“fopen”的效果,但是如果想要改变访问文件的方式就得利用flag参数。

    代码:

     1 #include<unistd.h>2 #include<stdio.h>3 #include <sys/types.h>4 #include <sys/stat.h>5 #include <fcntl.h>6 #include<string.h>7 8 9 int main()10 {11   int fd=open("open.txt",O_WRONLY | O_CREAT ,0664);12   if(fd == -1)13   {14     perror("open file falied\n");15     return -1;16   }17 18   const char str[]="这是一段用于检测open函数参数的示例\n";                                                                                                                                                   19   write(fd,str,sizeof(str));20   return 0;21 }
    

    结果

    第三个参数mode

    利用open函数的mode参数,可以对创建的文件进行权限管理,如果打开的文件已存在,那么该参数也无需去专门设置,设为0就好,但是不能不设置,否则会出现文件的权限错误。

    例如,将mode设置为0666,则文件创建出来的权限如下:

    按照之前的权限理解,我们创建的文件应该是具有所以的读写执行权限的。

    但实际上创建出来文件的权限值还会受到umask(文件默认掩码)的影响,实际创建出来文件的权限为:mode&(~umask)。umask的默认值一般为0002,当我们设置mode值为0666时实际创建出来文件的权限为0664。

    若想创建出来文件的权限值不受umask的影响,则需要在创建文件前使用umask函数将文件默认掩码设置为0。
    当然我并不建议对系统默认的值进行太多的修改。

    open的返回值

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

    当然啥是文件描述符在第三部分会有专门的介绍。


    2.2 write函数 

    接口

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

     man手册

    参数分析

    • fd:文件描述符。
    • buf:指向的是要写入数据的内存空间。
    • count:要写入的字节数。

    我们可以使用write函数,将buf位置开始向后count字节的数据写入文件描述符为fd的文件当中。

    • 如果数据写入成功,实际写入数据的字节个数被返回。
    • 如果数据写入失败,-1被返回。

    演示:

    #include<stdio.h>
    #include<unistd.h>
    #include<sys/types.h>
    #include<sys/stat.h>
    #include<fcntl.h>
    #include<string.h>int main()
    {int fd=open("Write.txt",O_WRONLY | O_CREAT,0666);if(fd < 0){perror("open");return 1;}const char* message ="Hello world 0.6\n";for(int i=0;i<10;i++)write(fd,message,strlen(message));return 0;
    }

    注:在上面的例子当中,我们不能使用sizeof函数充当write的第三个参数,因为message是一个指针,它不是一个字符数组。 

    注: 向文件写入数据时,是先将数据写入到对应文件的缓冲区当中,然后定期将缓冲区数据刷新到磁盘当中

    2.3 read函数

    接口:read():读取文件

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

    man手册

    • 参数

      • fd:文件描述符(由 open 返回)。

      • buf:数据读取的缓冲区地址。

      • count:期望读取的字节数。

    • 返回值:实际读取的字节数(可能小于 count),0 表示文件结束,-1 表示错误。

    演示:

      1 #include<stdio.h>2 #include<unistd.h>3 #include<sys/types.h>4 #include<sys/stat.h>5 #include<fcntl.h>6 #include<unistd.h>7 #define SIZE 10248 9 int main()10 {11         int fd=open("Write.txt",O_RDONLY,0666);12         if(fd < 0)13         {14                 perror("open failed:\n");15                 return 1;16         }17         char message[1024];18         ssize_t n=read(fd,message,sizeof(message));19         printf("这是读取到的数据:%s",message);20         return 0;21 }

     

    2.4close函数 

    接口:close()

    1 #include <unistd.h>
    2 int close(int fd);
    • 参数:要关闭的文件描述符。

    • 返回值:0 成功,-1 失败。

    当然这个函数是在是太简单了,这里就不在赘述。

    演示: 

      1 #include<stdio.h>2 #include<unistd.h>3 #include<sys/types.h>4 #include<sys/stat.h>5 #include<fcntl.h>6 #include<unistd.h>7 #define SIZE 10248 9 int main()10 {11         int fd=open("Write.txt",O_RDONLY,0666);12         if(fd < 0)13         {14                 perror("open failed:\n");15                 return 1;16         }17         char message[1024];18         ssize_t n=read(fd,message,sizeof(message));19         printf("这是读取到的数据:%s",message);20         close(fd);21         return 0;22 }


     三、文件描述符fd

    3.1文件描述符的概念

    文件是由进程运行时打开的,一个进程可以打开多个文件,而系统当中又存在大量进程,这就导致了,在系统中任何时刻都可能存在大量已经打开的文件。
    因此,操作系统务必要对这些已经打开的文件进行管理,操作系统会为每个已经打开的文件创建各自的struct file结构体,然后将这些结构体以双链表的形式连接起来,之后操作系统对文件的管理也就变成了对这张双向链表的增删查改的操作。而在我们学习过进程相关概念后,我们也明白进程之间也是存在一个PCB结构体的。
    而为了区分已经打开的文件哪些属于特定的某一个进程,我们就还需要建立进程结构体和文件结构体之间的对应关系。

    进程和文件之间的对应关系是如何建立的?

     我们知道,当一个程序运行起来时,操作系统会将该程序的代码和数据加载到内存,然后为其创建对应的task_struct、mm_struct、页表等相关的数据结构,并通过页表建立虚拟内存和物理内存之间的映射关系。

    而task_struct当中有一个指针,该指针指向一个名为files_struct的结构体,在该结构体当中就有一个名为fd_array的指针数组(又被称为文件描述表),该数组的下标就是我们所谓的文件描述符。
    当进程打开log.txt文件时,我们需要先将该文件从磁盘当中加载到内存,形成对应的struct file,将该struct file连入文件描述符表,并将该结构体的首地址填入到fd_array数组当中下标为3的位置,使得fd_array数组中下标为3的指针指向该struct file,最后返回该文件的文件描述符给调用进程即可。

    这也是为啥文件描述符是一个整数,因为:它本质上是一个数组下标。

    3.2文件描述符与FILE*的区别

    虽然C语言提供了FILE *类型和相关的标准库函数来处理文件操作,但底层实际上是通过文件描述符来进行管理的。理解FILE *与文件描述符的区别对于深入理解文件I/O非常重要。

    1. 特性             FILE *(C标准库)                  文件描述符(Linux操作系统)
    2. 类型            由C标准库提供的类型                 操作系统内核使用整数值标识
    3. 管理者         由C标准库管理                           由操作系统内核管理
    4. 主要用途     提供更高级别的文件操作接口     提供更低级别的文件操作接口
    5. 缓冲区管理  提供缓冲区管理,提高效率        不提供缓冲区管理
    6. 数据访问方式 适用于文本文件的高级操作      适用于二进制文件和直接内存映射操作

    四.文件描述符fd分配规则


          4.1. 最小可用原则:

                    新打开的fd选择当前未被使用的最小整数【如关闭fd (0)后新文件占用0】。

          4.2演示:

      1 #include<stdio.h>2 #include<unistd.h>                                                                                           3 #include<sys/types.h>                                                                                        4 #include<sys/stat.h>                                                                                       5 #include<fcntl.h>                                                                                          6 #include<unistd.h>7 8 int main()9 {10         int fd1=open("Write.txt",O_RDONLY,0666);11         printf("这是关闭其他文件描述符之前的fd:%d\n",fd1);12         close(0);13         close(fd1);14         close(2);15         int fd2=open("Write.txt",O_RDONLY,0666);16         printf("这是关闭其他文件描述符之后的fd:%d\n",fd2);17         return 0;18 }

    解释:
    先打开一个文件,发现该文件的描述符是3【也很好理解,毕竟上面还有标准输入/输出/错误3者】,然后关闭标准输入、标准错误与该文件描述符【不关闭二,是我们后面还要打印fd观察现象】 ,在打开文件,发现描述符fd变成了0。

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

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

    相关文章

    快速了解Go+rpc

    更多个人笔记&#xff1a;&#xff08;仅供参考&#xff0c;非盈利&#xff09; gitee&#xff1a; https://gitee.com/harryhack/it_note github&#xff1a; https://github.com/ZHLOVEYY/IT_note 文章目录 rpc基础概念GO的rpc应用简单编写json编写rpc rpc基础概念 电商系统…

    基于大模型的膀胱肿瘤全周期诊疗方案研究报告

    目录 一、引言 1.1 研究背景与意义 1.2 研究目的与方法 1.3 国内外研究现状 二、大模型预测膀胱肿瘤的原理与技术基础 2.1 大模型介绍 2.2 预测原理 2.3 技术支撑 三、术前风险预测与准备方案 3.1 肿瘤分期与恶性程度预测 3.2 患者身体状况评估 3.3 术前准备工作 …

    2025年4月个人工作生活总结

    本文为 2025年4月工作生活总结。 研发编码 一个项目的临时记录 自2月份领导让我牵头负责一个项目起&#xff0c;在本月算是有较多时间投入——但也是与之前的相比。 月初&#xff0c;清明节前一晚上&#xff0c;因某事务被叫上参加临时紧急远程会议&#xff0c;几方领导都在…

    Python爬虫实战:获取软科网最新特定专业大学排名数据并做分析,为高考填报志愿做参考

    一、引言 在高考升学的重要阶段,志愿填报成为考生和家长关注的核心问题。准确、全面且具有权威性的大学专业排名数据,是考生做出科学志愿决策的关键依据。软科网作为专业的大学排名信息发布平台,其发布的计算机科学与技术专业排名数据,因具有较高的公信力和参考价值,备受…

    自学S32k144(18)————芯片锁死问题及成功解锁流程

    1.锁死原因 温度过高flash异常操作静电等电压异常问题。。。。 本人出现情况&#xff1a;之前开发板不知什么原因&#xff0c;发生短路&#xff0c;重新置换芯片后&#xff0c;发现芯片在S32DS中无法正常烧录 判断可能是由于焊接时温度过高导致锁死。需解锁芯片。 2.解决方法…

    ISIS的由于L1产生的一系列问题

    如果有些名词不清晰可以查看之前文章 L1访问其他区域使用缺省路由会引发次优路径问题&#xff0c;但次优路径leak路由又会引发路由环路问题&#xff0c;下面将会从去缺省路由到路由环路一一解决 Level 1的缺省路由 L1访问其他区域使用缺省路由 --> 引发次优路径 --> 引…

    C++继承(下)

    目录 一、继承与友元 二、继承与静态成员 三、菱形继承及菱形虚拟继承 1. 继承的方式 2. 菱形继承的问题 3. 菱形虚拟继承 4. 虚拟继承解决数据冗余和二义性的原理 4.1 普通菱形继承的内存布局 4.2 虚拟继承的内存布局 四、继承的总结和反思 1. 多继承的复杂性 2.…

    【漫话机器学习系列】233.激活阈(Threshold Activation)

    深度学习入门&#xff1a;了解“阈值激活函数”&#xff08;Threshold Activation Function&#xff09; 激活函数是神经网络中至关重要的一环。今天&#xff0c;我们通过一幅简单直观的手绘图&#xff0c;一起理解最早期也最基础的激活函数之一 —— 阈值激活函数&#xff08;…

    (4)python中jupyter lab使用python虚拟环境

    1. 先了解IPython和IPyKernel简介 IPython 是一个功能强大的交互式 Python 解释器和开发环境。它提供了一种增强的 Python Shell,使得用户能够以交互的方式探索、分析和可视化数据。IPython 的名称来源于 "Interactive Python",体现了其交互式的特性。 IPyKernel 是…

    nginx 配置要领

    你提出的问题非常好&#xff01;确实在配置 WebSocket 代理时&#xff0c;proxy_pass 的 URL 处理需要特别注意。以下是关键解释和修正建议&#xff1a; 1. 原配置的问题分析 location /ws/ {proxy_pass http://fastapi-container:8000; # 会保留 /ws/ 前缀传递给后端 }这种配…

    【AI】DeepSeek 流程图 / 时序图制作,Word 排版错乱问题,文字转直观图形

    一&#xff1a;动态流程图 / 时序图制作&#xff08;DeepSeek Draw.IO&#xff09; 工具准备 DeepSeek&#xff08;AI 生成代码&#xff09;&#xff1a;官网&#xff08;免费&#xff09;Draw.IO&#xff08;可视化渲染&#xff09;&#xff1a;官网&#xff08;免费&#…

    4. python3基本数据类型

    Python3 中有六个标准的数据类型&#xff1a; Number&#xff08;数字&#xff09; String&#xff08;字符串&#xff09; List&#xff08;列表&#xff09; Tuple&#xff08;元组&#xff09; Set&#xff08;集合&#xff09; Dictionary&#xff08;字典&#xff09; Pyt…

    WPF之TextBox控件详解

    文章目录 1. TextBox概述2. 基本属性与功能3. 输入控制详解3.1 MaxLength3.2 AcceptsReturn3.3 AcceptsTab3.4 CharacterCasing3.5 IsUndoEnabled3.6 自定义输入限制 4. 文本选择与操作4.1 选择属性4.2 选择方法4.3 文本操作4.4 选择事件4.5 实现自定义文本处理功能 5. 滚动支持…

    1.4 点云数据获取方式——结构光相机

    图1-4-1结构光相机 结构光相机作为获取三维点云数据的关键设备,其工作原理基于主动式测量技术。通过投射已知图案,如条纹、点阵、格雷码等,至物体表面,这些图案会因物体表面的高度变化而发生变形。与此同时,利用相机从特定

    【MATLAB第118期】基于MATLAB的双通道CNN多输入单输出分类预测方法

    【MATLAB第118期】基于MATLAB的双通道CNN多输入单输出分类预测方法 一、双通道CNN简介 在深度学习领域&#xff0c;卷积神经网络&#xff08;CNN&#xff09;凭借其强大的特征提取能力&#xff0c;已成为图像识别、自然语言处理等任务的核心技术。传统单通道CNN在处理单一模态…

    2025上海车展 | 移远通信推出自研NG-eCall QuecOpen方案,助力汽车安全新标准加速落地

    4月29日&#xff0c;在2025上海国际汽车工业展览会期间&#xff0c;全球领先的物联网和车联网整体解决方案供应商移远通信宣布&#xff0c;正式发布自主研发的NG-eCall&#xff08;下一代紧急呼叫系统&#xff09;QuecOpen解决方案。 该方案凭借高度集成的软硬件协同设计&…

    leetcode76

    目录 803ms超时。。。。越改越超时。。。 一些纠缠 代码分析&#xff1a; 代码问题&#xff1a; 改进建议&#xff1a; 示例代码&#xff1a; The error message you’re seeing indicates that there is a reference binding to a null pointer in your code. This typ…

    大数据应用开发和项目实战-Seaborn

    一、Seaborn概述 Seaborn是基于Python数据可视化库Matplotlib开发的扩展库&#xff0c;专注于统计图形的绘制&#xff0c;旨在通过简洁的代码实现复杂数据的可视化&#xff0c;帮助用户更轻松地呈现和理解数据。其核心设计目标是简化统计可视化流程&#xff0c;提供高级接口和美…

    数据科学与计算

    Seaborn的介绍 Seaborn 是一个建立在 Matplotlib 基础之上的 Python 数据可视化库&#xff0c;专注于绘制各种统计图形&#xff0c;以便更轻松地呈现和理解数据。 Seaborn 的设计目标是简化统计数据可视化的过程&#xff0c;提供高级接口和美观的默认主题&#xff0c;使得用户…

    深入浅出循环神经网络(RNN):原理、应用与实战

    1、引言 在深度学习领域&#xff0c;循环神经网络&#xff08;Recurrent Neural Network, RNN&#xff09;是一种专门用于处理**序列数据**的神经网络架构。与传统的前馈神经网络不同&#xff0c;RNN 具有**记忆能力**&#xff0c;能够捕捉数据中的时间依赖性&#xff0c;广泛应…