【LInux】<基础IO> 文件操作 | 文件描述符 | 重定向

在这里插入图片描述

👦个人主页:Weraphael
✍🏻作者简介:目前正在学习c++和算法
✈️专栏:Linux
🐋 希望大家多多支持,咱一起进步!😁
如果文章有啥瑕疵,希望大佬指点一二
如果文章对你有帮助的话
欢迎 评论💬 点赞👍🏻 收藏 📂 加关注😍


目录

  • 一、C语言文件操作
      • 1.1 打开文件 --- fopen
      • 1.2 关闭文件 --- fclose
      • 1.3 文件写入 --- fwrite
  • 二、文件系统调用
      • 2.1 文件系统调用和函数的关系
      • 2.2 打开文件 --- open
      • 2.3 文件关闭 --- close
      • 2.4 文件写入 --- write
  • 三、文件描述符
      • 3.1 什么是文件描述符
      • 3.2 三个标准流
      • 3.3 文件描述符的分配规则
      • 3.4 引用计数
  • 四、再谈重定向
      • 4.1 输出重定向
      • 4.2 追加重定向
      • 4.3 输入重定向
      • 4.4 系统调用接口 --- dup2
  • 五、补充知识
      • 5.1 stdout和stderr的区别
      • 5.2 为什么Linux下一切皆文件(以源码的角度剖析)
  • 六、相关代码

一、C语言文件操作

1.1 打开文件 — fopen

#include <stdio.h>
FILE* fopen(const char* path, const char* mode);
  • path:要打开文件的相对路径或绝对路径。注意:如果不带路径默认会在当前进程所在路径下创建/打开文件

  • mode:打开文件的模式常用的模式包括:

    • "r":只读模式。打开文件用于读取。注意:文件不存在表示打开文件失败。
    • "w":写入模式。文件内容截断为零长度,即清空文件内容,再写入内容。(如果文件不存在,系统会新建对应的文件)
    • "a":追加模式。不会清空原有文件内容,而在文件内容末尾追加。(如果文件不存在,系统会新建对应的文件)
    • 还有很多模式请查看手册:man fopen
  • 返回值

    • 打开文件后,将返回一个指向 FILE 类型的文件指针,指向打开的文件流。

    • 如果打开失败,则返回 NULL

请添加图片描述

请添加图片描述

为什么不带路径默认会在当前进程所在路径下创建文件?为什么不在其他路径创建文件?

首先大家需要明白一个道理:文件一定是由进程通过调用函数(如fopen())打开的,因此,文件与进程有关。所以,默认情况下,如果你不带路径,新建文件所处的路径将取决于进程当前的工作目录。

当然了,如果你的程序在运行时改变了当前工作目录,那么新建文件所处的路径也会相应地改变。

请添加图片描述

请添加图片描述

1.2 关闭文件 — fclose

C语言中,当你完成了对文件的读写操作后,最后应该使用fclose函数关闭文件。这是一个很重要的步骤,因为它确保了操作系统释放文件资源,并且在某些情况下,确保了写入的数据被刷新到磁盘上。不关闭文件可能会导致资源泄露或数据丢失

int fclose(FILE* stream);
  • 如果成功关闭文件,fclose函数返回0

  • 如果关闭失败,返回EOF-1),表示出现了错误。

1.3 文件写入 — fwrite

C语言对于文件写入有这几种方式:fputcfputsfwritefprintfsnprintf(大家可以去man手册查看用法)

int fputc (int character, FILE* stream);
int fputs (const char* str, FILE* stream);
int snprintf ( char* s, size_t n, const char* format, ...);

这里以fwrite函数为例

size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);

这个函数将 nmemb 个元素,每个元素大小为 size 字节,从指针 ptr 所指向的内存块写入到给定的文件流 stream 中。

  • ptr:指向待写入数据的指针。

  • size:数据写入的字节数。

  • nmemb:以size为单位,待写入数据的数量。

  • stream:指向FILE对象的指针。

  • 返回值:如果返回值与 nmemb 不相等,说明写入时发生错误。

请添加图片描述

这里有一个细节问题:strlen需要+ 1’\0‘写入到log.txt文件中吗?

我们执行以上代码看看log.txt里的内容(不+ 1

请添加图片描述

然后我们再+ 1看看效果

请添加图片描述

后面多了一个类似于乱码的字符^@,这其实就是'\0'的二进制。因为vim是一个文本编辑器,对于二进制来说当然显示的是乱码啦。 这也说明了我们在向文件写入字符串的时候不需要处理'\0'(只需将字符串的内容写入即可),因为字符串以'\0'结尾是编程语言的规定,和文件没半毛钱关系 ~

接下来我们再连续执行程序,再看看log.txt的内容

请添加图片描述

我们不是向文件中写入了多个字符串hello file吗?为什么只写入了一个?

这是因为我们设置打开文件的模式是w,即在向文件写入之前会先对文件进行清空处理,然后再写入。

这不由得让我们联想到输出重定向>

请添加图片描述

因此输出重定向>的底层一定要以w的方式打开一个文件,即fopen("文件/文件路径", "w"),即将文件内容清空,最后再用写入函数进行向文件写入


接下来我们再以a的方式打开一个文件并写入

请添加图片描述

请添加图片描述

我们发现:a的方式打开一个文件并写入,不会清空文件,而是在文件内容末尾追加。

这不由得让我们联想到追加重定向>>

请添加图片描述

因此追加重定向>>的底层一定要以a的方式打开一个文件,即fopen("文件/文件路径", "a"),即不将文件内容清空,最后再用任意一个写入函数向文件内容进行追加

综上所述,输出重定向>和追加重定向>>主要区别就是在于打开文件的方式不同,一个以w,一个以a

请添加图片描述

二、文件系统调用

2.1 文件系统调用和函数的关系

我们知道,文件是在磁盘上存储的,磁盘作为外设(外部设备),所以访问文件其实也是在访问磁盘(硬件)!而我们计算机体系结构是分层的,如下所示:

在这里插入图片描述

而我们知道底层硬件一定要被操作系统管理的,作为普通用户无法直接访问底层硬件的相关信息,那么就只能通过管理者,也就是操作系统来获取,而操作系统根本不相信用户,因此提供了系统调用接口来访问,以此来保护操作系统。因此,几乎所有的库函数只要访问硬件设备,必定要封装系统调用接口。因此,以上文件操作的函数底层必定封装了文件系统调用接口!

2.2 打开文件 — open

Linux中,open函数是一个系统调用,用于打开或创建文件

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>// 通常用于打开已存在文件
int open(const char *pathname, int flags); // 通常用于打开不存在文件
int open(const char *pathname, int flags, mode_t mode);
  • pathname:要打开或创建的文件的路径。不指定路径默认是当前进程的工作路径。

  • flags:控制文件打开方式。以下是常见的打开方式。(还有很多打开方式,可以通过man 2 open来查看)

    • O_WRONLY:以只写模式打开文件。
    • O_CREAT:如果文件不存在,则创建文件。
    • O_APPEND:在写入时将数据追加到文件的末尾。
    • O_TRUNC:清空文件内容。

    实际上,以上的选项是在<fcntl.h>头文件中定义的。我们可以在路径/usr/include/bits查看,此路径通常包含了与体系结构相关的宏定义和声明。

在这里插入图片描述

  • mode:用于指定新创建文件的权限,只有在 O_CREAT 标志位被设置时才有效。一般采用八进制表示的文件权限值,例如 0666

  • 返回值:

    • 如果成功,返回一个文件描述符(非负整数),该描述符可以在后续的读写操作中传参。

    • 如果失败,返回-1

请添加图片描述

请添加图片描述

当我们将程序运行起来,发现open打开文件失败,原因是:O_WRONLY只会读文件,而不会新建文件。那就非常简单了,再加一个宏O_CREAT,让文件不存在时自动创建即可。可是,open的第二个参数flag是整型,如何传两个参数?

这就要涉及到比特位方式的标志位传递方式

还记得诸如O_WRONLY这些宏吗?它们的共同特点:二进制序列中最多只有一个比特位上是1,并且1所处的比特位是不同的。而一个整型是4个字节,也就是32个比特位(标志位),那么我们可以使用按位或|运算符来组合多个标志位。比如0001 | 0010 = 0011。然后open函数内部实现可以使用按位与操作符&来检查是否设置了某个标志位,比如

请添加图片描述

请添加图片描述

因此,我们可以对一开始的代码进行修改,使用按位或|增加O_CREAT选项

请添加图片描述

请添加图片描述

如上,我们确实把一个不存在的文件log.txt创建好了,可是此文件的权限都是乱码,原因在于你新建一个文件,此文件要受Linux权限约束,你新建文件的权限必须得告诉操作系统。因此,只有在 O_CREAT 标志位被设置时,需要指定新文件的权限

在往期博客讲过,文件默认的权限是0666,即rw-rw-rw-

请添加图片描述

请添加图片描述

文件创建出来了,并且权限也不是乱码了,但是,权限并不是我们一开说的rw-rw-rw-。实际上创建出来的文件会收到文件默认权限掩码umask的影响实际创建出来文件的权限值为:mode & (~umask);而在Linux中,umask的默认权限值为0002,当我们设置mode值为0666时实际创建出来的文件权限为0666 & ~(0002) = 0664,即rw-rw-r--

若想创建出文件的权限值不受umask的影响,即如上想让权限为rw-rw-rw-,那么系统专门提供了 umask系统调用接口,可以让你修改默认的权限掩码。

即在创建文件前使用umask函数将文件掩码umask设置为0

请添加图片描述

请添加图片描述

2.3 文件关闭 — close

#include <unistd.h>
int close(int fd);
  • fd 是要关闭的文件描述符,即open函数的返回值。

  • 函数返回值为0表示成功关闭文件,返回-1表示出现错误

关闭文件描述符后,相关的系统资源将被释放,包括文件表项和文件描述符本身。这通常是在不再需要使用文件描述符时执行的操作,以释放系统资源并防止资源泄漏。

2.4 文件写入 — write

#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
  • fd 是文件描述符(open函数返回值),表示要写入的文件。
  • buf 是一个指向要写入数据的缓冲区的指针。
  • count 是要写入的字节数。
  • 返回值是写入的字节数,如果出现错误,则返回-1

如果想要实现输出重定向的功能,不仅需要读O_WRONLY、创建文件O_CREAT,在写之前还需要将文件清空O_CREAT

请添加图片描述

请添加图片描述

如果想实现追加重定向也非常简单,由于清空和追加两个是冲突的,因此你只需要将清空O_CREAT替换成追加O_APPEND

请添加图片描述

请添加图片描述

【总结】

请添加图片描述

因此,只要是在 Linux 平台中编写的程序,无论是什么编程语言,在进行文件相关操作时,其文件操作函数都有封装系统调用接口。也就是说,要想与硬件(磁盘)打交道,必须经过 系统调用 -> 操作系统 -> 硬件 这条路线,否则无法直接与硬件进行交互。

三、文件描述符

3.1 什么是文件描述符

到目前为止,我们所知道的文件描述符就是open函数的返回值(非负整数),这个描述符可以在后续的读写操作中用作文件标识符,即找到对应的文件。

那不知道大家有没有思考过一个问题:为什么操作系统可以单单通过一个整数(文件描述符)就能找到对应的文件?

文件分为打开的文件没打开的文件(这里先讨论打开的文件,等到文件系统再谈没打开的文件)。打开的文件是由进程使用函数(如fopen())打开的。根据冯诺依曼体系结构,被打开的文件一定会被加载到内存。而一个进程可以打开多个文件(1:n),那么被打开的文件也一定要受操作系统的管理,那就要请出管理的六字真言:先描述,后组织。

  • 描述:一个被打开的文件一定要有自己的文件结构体对象file,包含文件的信息,即struct file { 文件信息; struct file* next; struct file* prev;};

  • 组织:通过双链表方式。

  • 往后对被打开文件的管理,就转换成为了对链表的增删改查!

所以,当进程打开文件时,操作系统会在内核中创建数据结构来描述这个已打开的文件对象(和PCB类似)。这个数据结构通常被称为 file 或其他类似的名字,它包含了文件的各种信息,如文件位置、权限、状态等。

而进程可以打开多个文件,那进程PCB结构体对象就要存储哪些文件是由哪一个进程打开的。因此,每个进程PCB对象都要和打开的文件建立关系!所以进程PCB对象其实有一个指针struct files_struct* files,这个指针指向结构体files_struct,而这个结构体包含一个指针数组struct file* fd_array[],这个数组我们可以称之为文件描述符表。数组中的每个元素都是指向当前进程所打开文件的指针(地址)!

所以,本质上文件描述符就是指针数组的下标(索引)。所以,只要拿着文件描述符,就可以找到对应的文件。

请添加图片描述

【源码】

请添加图片描述

我们可以打印出文件描述符来看看

请添加图片描述

请添加图片描述

3.2 三个标准流

如上,文件描述符即指针数组的下标是从3开始连续递增的。那这里我有一个问题:为何不从0开始递增呢?难道下标01、``2存储了其他被打开文件的地址吗?你的猜测是正确的!

在C语言中,默认情况下,当一个进程启动时,操作系统会打开三个标准流(本质上就是文件,不同的编程语言都会打开它的三个标准流)

  • stdin:标准输入,文件描述符 0。通常用来接收用户的输入,主要是键盘设备。

  • stdout:标准输出,文件描述符 1。通常用来输出程序的正常运行信息,主要是显示器设备。

  • stderr 标准错误,文件描述符 3。通常用来输出程序的错误信息,stderr 默认也将错误信息显示在终端上。主要也是显示器。

请添加图片描述

我们可以来验证:

请添加图片描述

FILEC语言封装文件操作的结构体,当你使用 C 标准库中的函数来操作文件时,这些库函数底层必定会封装系统调用接口,那么FILE结构体内部一定要有对应的文件描述符来与操作系统进行通信,即需要有文件描述符来调用底层封装的系统调用接口,因此FILE结构体里一定会包含文件描述符成员_fileno(其他编程语言的文件操作也是如此)

请添加图片描述

请添加图片描述

3.3 文件描述符的分配规则

如果是直接打开文件某个文件,由于系统默认会打开三个标准流,因此新分配的文件描述符从3开始依次递增。

请添加图片描述

请添加图片描述

如果我在打开log.txt文件之前,把标准输入stdin关闭,其文件描述符还会是3吗?

请添加图片描述

请添加图片描述

我们发现:新文件的文件描述符占据了标准输入stdin的文件描述符。因此,文件描述符的分配规则是:从头遍历文件描述符表fd_array[],找到一个最小的且没有被使用的下标,它的下标就是新文件的文件描述符(保证数组空间不会被浪费)。

3.4 引用计数

如果我这里故意将文件标识符1给关掉,即显示器文件被关闭,那么打印结果就无法显示到屏幕上

请添加图片描述

请添加图片描述

那如果我在文件标识符1关掉的基础上,再向stderr流写入,即向显示器写入,还能写入成功吗?有的人想,肯定不成功,文件标识符1关掉,等同将显示器文件关掉,而stderr也是将结果显示在显示器,肯定打印不出来

请添加图片描述

请添加图片描述

我们发现:结果可以打印出来。

其实每个文件对象都包含一个引用计数字段count,记录了有多少个文件描述符指向该文件对象。当一个进程打开一个文件时,内核会增加该文件对象的引用计数count++。当进程关闭文件描述符时,内核会减少相应文件对象的引用计数count--,并且将文件描述符表对应下标的位置置空NULL。只有当引用计数减少到零时,内核才会释放该文件对象及其相关资源。

在这里插入图片描述

四、再谈重定向

重定向实际上是改变了进程的文件描述符表中指针数组对应下标内容的指向。这样,进程在进行I/O操作时,就会按照新的文件描述符表中的指向来进行,从而实现了重定向的效果。

常见的重定向操作包括

  • 将一个文件描述符指向另一个文件描述符

  • 或者将一个文件描述符关闭。

4.1 输出重定向

输出重定向是指将程序本来输出到标准输出stdout设备的内容,重定向到其他文件

请添加图片描述

请添加图片描述

此时,我们发现,本来应该输出到显示器上的内容,输出到了文件log.txt当中,这不就是典型的输出重定向!

接下来我们来分析,为什么会出现这种情况

代码中,首先将stdout文件关闭,而后打开log.txt文件。根据文件描述符的分配规则是:从头遍历文件描述符表fd_array[],找到一个最小的且没有被使用的下标,它的下标就是新文件的文件描述符(保证数组空间不会被浪费)。那么log.txt的的文件描述符就是1,而后面写入文件是向文件描述符1中写入,即就是向log.txt文件写入。这就是重定向的原理。

请添加图片描述

4.2 追加重定向

追加重定向是指将程序本来输出到标准输出stdout设备的内容,追加到指定文件的末尾,而不是覆盖原文件内容。

那我们只需将以上代码的打开方式O_TRUNC修改成O_APPEND就有追加重定向的效果

请添加图片描述

请添加图片描述

4.3 输入重定向

输入重定向是指将程序从标准输入stdin中读取数据的方式改变为从其他文件读取数据

例如,让本应该从“键盘文件”读取数据,改从log.txt文件中读取数据,那么我们可以打开log.txt文件之前将stdin文件关闭,这样一来,根据文件描述符的分配规则,当我们后续打开log.txt文件时所分配到的文件描述符就是0

请添加图片描述

请添加图片描述

4.4 系统调用接口 — dup2

以上操作都需要先关闭再打开一个文件来实现重定向,操作过于繁琐,而且每次你写这样的代码都要向别人解释,因此操作系统提供了系统调用接口来实现重定向操作

#include <unistd.h>
int dup2(int oldfd, int newfd);        
  • oldfd :是要复制的文件描述符。

  • newfd :是要被覆盖的文件描述符。

  • 如果 newfd 已经打开,则操作系统首先会关闭 newfd,即释放文件对象。然后,dup2() 会使 newfd 指向 oldfd 所指向的文件对象。

下面是演示了如何使用 dup2() 函数将标准输出重定向到一个文件中:

请添加图片描述

请添加图片描述

下面是演示了如何使用 dup2() 函数将标准输出追加重定向到一个文件中:

请添加图片描述

请添加图片描述

下面是演示了如何使用 dup2() 函数将标准输入重定向到一个文件中:

请添加图片描述

请添加图片描述

为往期模拟实现bash添加重定向功能:点击跳转

五、补充知识

5.1 stdout和stderr的区别

我们至今所认知的标准输出流和标准错误流并没有区别,都是将数据向显示器打印。请添加图片描述

请添加图片描述

但若是将程序运行结果重定向输出到文件hello.txt当中,我们会发现hello.txt文件当中只将标准输出的打印语句重定向到hello.txt文件中,而向标准错误流输出的两行数据并没有重定向到文件当中,而是仍然输出到了显示器上。

请添加图片描述

实际上我们使用重定向时,默认重定向的是文件描述符是1的标准输出流,而并不会对文件描述符是2的标准错误流进行重定向。

此外,我们也可以将标准错误流进程重定向,通常使用 2>2>> 来重定向 stderr。详细命令如下:

./proc 1> hello.txt 2>stderr.txt 
//不要在重定向操作符和文件描述符之间添加空格。
// 1可以被省略,因为它是默认的输出流。

上述指令做了两次重定向,第一次把标准输出重定向到了文件描述符为1的显示器,第二次是把标准错误重定向到了文件描述符为2的显示器,,通过重定向可以分别将它们发送到不同的目的地,使得对程序输出和错误信息的处理更加灵活和有效。

前面已经提到,重定向只会默认把标准输出的进行处理,并不会重定向标准错误,如果我想让标准输出和标准错误一同混合起来到一个文件显示,如下命令:

./myfile 1>all.txt 2>&1

这个命令将 myfile的标准输出重定向到 all.txt 文件,2>&1 是将标准错误重定向到与标准输出相同的地方,也就是all.txt 文件中。

5.2 为什么Linux下一切皆文件(以源码的角度剖析)

一切皆文件其实是在Linux系统中一致访问资源的方式,即将所有资源抽象为文件。这包括了硬件设备等各种资源。(文件很容易理解,这里主要谈为什么硬件也要当做文件来看待)

当一个进程在Linux系统中运行时,操作系统会为每个文件创建一个文件对象struct file,这个文件对象跟踪了该文件的状态和相关信息。

因此,当一个进程打开硬件,那么操作系统就会管理这个硬件,即为该硬件创建文件对象struct file,而此文件对象其实提供了对设备的操作接口。

请添加图片描述

f_op指向对文件操作的各种函数指针。这些函数指针对应了文件的不同操作,例如读取、写入、定位等。

请添加图片描述

所以所谓的一切皆文件,就是相当于在文件这一层封装了一个文件对象,让文件对象中的函数指针结构体 file_operations 指向不同设备的操作方法。在这种情况下,不同类型的文件对象(比如普通文件、设备文件等)都具有相同的接口,即结构体file_operations。当应用程序调用文件操作函数时,操作系统根据文件对象的实际类型来调用相应的方法,这种行为类似于多态的表现,即同一个接口可以根据不同的对象类型展现出不同的行为。

因此,一切皆文件可以被视为在操作系统级别实现的一种多态思想,使得不同类型的资源都能够以统一的方式进行访问和管理。

六、相关代码

本篇博客相关代码:点击跳转

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

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

相关文章

springboot004网页时装购物系统

springboot004网页时装购物系统 亲测完美运行带论文&#xff1a;获取源码&#xff0c;私信评论或者v:niliuapp 运行视频 包含的文件列表&#xff08;含论文&#xff09; 数据库脚本&#xff1a;db.sql其他文件&#xff1a;ppt.pptx论文/文档&#xff1a;开题报告.docx论文&…

独立服务器和云服务器哪个好?

在当今数字时代&#xff0c;网站托管是任何在线业务成功的关键要素之一。但是&#xff0c;当谈到选择正确的托管解决方案时&#xff0c;很容易陷入独立服务器与云服务器之间的抉择。两者都有各自的优势和限制&#xff0c;因此在决定哪种类型的托管适合您的业务之前&#xff0c;…

【线性系统理论】笔记二

状态转移矩阵-性质 特殊的矩阵指数函数 A求矩阵指数函数计算 方法1&#xff1a;特征值互异 方法2&#xff1a;特征值重根 方法3&#xff1a;反拉氏变换 方法4&#xff1a; 凯莱-哈密顿求e 特征值互异&#xff1a; 特征值相同 状态转移矩阵e求A 零输入响应 零状态响应 状态…

第189题|幂级数的展开的常规方法(二)|武忠祥老师每日一题

解题思路&#xff1a;将函数展开成幂级数有两种方法&#xff1a;一种是直接法&#xff08;这种一般比较麻烦&#xff09;&#xff0c;一种是拆解成现有展开式展开&#xff08;这种的特征一般是能因式分解&#xff09;。 第一步&#xff1a; 这里看到 ln(1-x-2x^2) 将里面的式…

AI大模型日报#0515:Google I/O大会、 Ilya官宣离职、腾讯混元文生图大模型开源

导读&#xff1a;欢迎阅读《AI大模型日报》&#xff0c;内容基于Python爬虫和LLM自动生成。目前采用“文心一言”&#xff08;ERNIE 4.0&#xff09;、“零一万物”&#xff08;Yi-34B&#xff09;生成了今日要点以及每条资讯的摘要。 《AI大模型日报》今日要点&#xff1a;谷歌…

高考志愿系统-模拟填报模块分析

1.获取所有志愿列表 接口: http://localhost:81/dev-api/college_entrance/aspiration/list 默认传参pageNum1&pageSize10&#xff0c; 请求方法: GET 接口内方法同样首先设置分页信息&#xff0c;然后修改查询出的所有志愿信息列表中的学生id属性 2.详细志愿查看 接口…

指针在函数的应用(C++)

一、传递地址 实参传递进函数体内后&#xff0c;生成的是实参的副本&#xff0c;在函数内改变副本的值并不影响实参。指针传递参数时&#xff0c;指针变量产生了副本&#xff0c;但副本与原变量指向的内存区域是同一个。改变指针副本指向的变量&#xff0c;就是改变原指针变量指…

哈希表的理解和实现

目录 1. 哈希的概念 (是什么) 2. 实现哈希的两种方式 (哈希函数) 2.1. 直接定址法 2.2. 除留余数法 2.2.1. 哈希冲突 3. 补充知识 3.1. 负载因子 3.2. 线性探测和二次探测 4. 闭散列实现哈希表 (开放定址法) 4.1. 开放定址法的实现框架 4.2. Xq::hash_table::insert…

vue2 配置运行环境

vue2 配置运行环境 在 vue2 项目中配置运行环境 在项目中新建 .env.development 文件 和 .env.production 文件 .env.development NODE_ENV development //指定当前环境模式 VUE_APP_MODE development VUE_APP_BASE_URL "/dev-api".env.production NODE_ENV &q…

万字长文破解 AI 图片生成算法-Stable diffusion (第一篇)

想象一下&#xff1a;你闭上眼睛&#xff0c;脑海中构思一个场景&#xff0c;用简短的语言描述出来&#xff0c;然后“啪”的一声&#xff0c;一张栩栩如生的图片就出现在你眼前。这不再是科幻小说里才有的情节&#xff0c;而是Stable Diffusion——一种前沿的AI图片生成算法—…

【电路笔记】-有源低通滤波器

有源低通滤波器 文章目录 有源低通滤波器1、概述2、有源低通滤波器2.1 一阶低通滤波器2.2 带放大功能的有源低通滤波器3、有源低通滤波器示例4、二阶低通有源滤波器通过将基本的 RC 低通滤波器电路与运算放大器相结合,我们可以创建一个具有放大功能的有源低通滤波器电路。 1、…

fastadmin对登录token的处理

fastadmin对token的操作 最近开发遇到一个场景&#xff0c;需要绕过验证获取登录&#xff0c;所以恶补了一下这个知识点&#xff0c;这个主要就是控制fastadmin的token的问题 代码分步实现 class Xcxuser extends Api {//关于鉴权protected $noNeedLogin [login,getopenid,…

1、sql server数据库进行sql注入

靶机取自&#xff1a;墨者sql server 1、判断数据库类型 抓包知sql server&#xff0c;所以注入语句跟MySQL有些区别 2、判断注入点 “http://219.153.49.228:42514/new_list.asp?id2 ”&#xff0c;当id2 and 11时显示正确&#xff0c;id2 and 12时页面报错。 3、确定列…

深度学习设计模式之抽象工厂模式

文章目录 前言一、介绍二、详细分析1.核心组成2.实现步骤3.代码示例4.优缺点优点缺点 5.使用场景 总结 前言 本文主要学习抽象工厂模式&#xff0c;抽象工厂模式创建的是对象家族&#xff0c;比如&#xff1a;苹果是一个产品&#xff0c;但是他不单单只生产手机&#xff0c;还…

回溯算法-组合问题-力扣第77题

什么是组合问题—— 举例&#xff1a; 有一个集合&#xff1a;{1,2,3,4} 现在要找出这个集合里面所有组合大小&#xff08;组合长度&#xff0c;组合里面数据的个数&#xff09;为2的组合 那么就有&#xff1a;总共6种组合 {1,2}&#xff0c;{1,3}&#xff0c;{1,4} {2,3}…

ubuntu在conda环境中使用 pip install -r requirements.txt但是没有安装在虚拟环境中

whereis pip pip listubuntu在conda环境中使用pip install lpips0.1.3 但是安装在了这里 Requirement already satisfied: lpips0.1.3 in /home/uriky/anaconda3/lib/python3.11/site-packages (0.1.3) 就会出现黄色波浪&#xff0c;未在虚拟环境中安装包 解决办法1&#xff1…

汇聚荣科技:如何有效为拼多多店铺引流?

在电商竞争激烈的今天&#xff0c;为拼多多店铺引流是每个店主必须面对的挑战。有效的引流策略不仅能增加店铺曝光度&#xff0c;还能提升转化率&#xff0c;促进销量增长。 一、社交媒体营销 利用微信、微博等社交平台进行推广&#xff0c;可以通过发布产品信息、用户评价和促…

GAME101-Lecture07学习

前言 今天主要讲shading&#xff08;着色&#xff09;。在讲着色前&#xff0c;要先讲图形中三角形出现遮挡问题的方法&#xff08;深度缓存或缓冲&#xff09;。 先采样再模糊错误&#xff1a;对信号的频谱进行翻译&#xff08;在这期间会有频谱的混叠&#xff09;&#xff…

Windows安装Django

1、下载Python程序包 Python程序包官网下载地址Download Python | Python.org,若下载最新版本&#xff0c;有最新版本则下载"Windows installer (64-bit)" 若是下载其他版本,可在下图位置找到相应的版本,然后点击Download.如下图所示&#xff1a; 打开后查看注意事项…

单位个人怎样向报社的报纸投稿?

作为一名单位的信息宣传员,我肩负着每月定期在媒体上投稿发表文章的重任。然而,在投稿的道路上,我经历了不少波折和挫折。 一开始,我天真地以为只要将稿件发送到报社的投稿邮箱,就能轻松完成任务。然而,现实却远比我想象的复杂。邮箱投稿的竞争异常激烈,编辑们会在众多稿件中挑…