当前位置: 首页 > news >正文

【Linux】重定向原理dup2缓冲区

文章目录

    • 重定向原理
      • 输出重定向
        • 关于FILE
        • 解释输出重定向原理
      • 追加重定向
      • 输入重定向
    • dup2
  • 缓冲区
      • 语言级别的缓冲区
      • 内核缓冲区

重定向原理

重定向的本质就是修改文件描述符下标对应的struct file*的内容

输出重定向

  • 输出重定向就是把本来应该输出到显示器的数据重定向输出到另一个文件当中

假设我们先关闭1标准输入,然后再打开一个文件,按照文件描述符的分配规则,给再打开文件分配的文件描述符fd就是1,那么是不是把输出的内容打印到屏幕上呢

image-20220701155706525

  • 由此现象,我们也可以看出,printf的底层是往fd=1的文件中打印内容,不关心该文件是什么

此时把本来应该打印到显示器的内容,显示到文件中,这种行为称为输出重定向


为什么是这样实现输出重定向呢?

  • close(1) ->断开了与显示器文件的联系, 相当于把fd_array[1]位置的内容置空
  • 然后再打开新文件log.txt,由文件描述符分配规则,fd_array[1]指向log.txt文件(存放log.txt文件的struct file的地址)

image-20220701160423572


所以C语言中的打印函数–printf,本质是往 标准输出(stdout)打印

image-20220701160557039


关于FILE

stdout和stdin和stderr的类型都是FILE*,是一个文件指针,那FILE到底 是什么呢?

FILE是C语言层面上的结构体

image-20220701161110371

库函数是对系统调用接口的封装,本质是访问文件都是通过文件描述符进行访问的,所以C库函数中的File结构体内部一定封装了文件描述符fd


以C语言的fwite函数为例子:该函数是向文件流中写入内容,然后实际在底层中 是通过文件描述符fd写到磁盘上

image-20220701161236596

所以我们可以推断, C语言的FILE结构体一定包含一个fd, C++中的cin,cout,cerr这些流对象的属性中也一定包含文件描述符fd

struct FILE
{//一定包含了一个整数,是对应在系统层面这个新打开文件的fd  
};

所以:语言上的in/out/err和系统上的012存在联系

  • stdin 标准输入,键盘 -> 包含fd = 1
  • stdout 标准输出,显示器 -> 包含fd = 2
  • stderr 标准输出,显示器 -> 包含fd = 3

我们可以在内核中看一下FILE的定义:

  • 其中的_filno就是文件描述符
//在/usr/include/libio.h
struct _IO_FILE {int _flags; /* High-order word is _IO_MAGIC; rest is flags. */
#define _IO_file_flags _flags//缓冲区相关/* The following pointers correspond to the C++ streambuf protocol. *//* Note: Tk uses the _IO_read_ptr and _IO_read_end fields directly. */char* _IO_read_ptr; /* Current read pointer */char* _IO_read_end; /* End of get area. */char* _IO_read_base; /* Start of putback+get area. */char* _IO_write_base; /* Start of put area. */char* _IO_write_ptr; /* Current put pointer. */char* _IO_write_end; /* End of put area. */char* _IO_buf_base; /* Start of reserve area. */char* _IO_buf_end; /* End of reserve area. *//* The following fields are used to support backing up and undo. */char *_IO_save_base; /* Pointer to start of non-current get area. */char *_IO_backup_base; /* Pointer to first valid character of backup area */char *_IO_save_end; /* Pointer to end of non-current get area. */struct _IO_marker *_markers;struct _IO_FILE *_chain;int _fileno; //!!!!!!!!!!!!!!!!!!!!!封装的文件描述符!!!!!!!!!!!!!!!!!!!!!
#if 0int _blksize;
#elseint _flags2;
#endif_IO_off_t _old_offset; /* This used to be _offset but it's too small. */
#define __HAVE_COLUMN /* temporary *//* 1+column number of pbase(); 0 is unknown. */unsigned short _cur_column;signed char _vtable_offset;char _shortbuf[1];/* char* _save_gptr; char* _save_egptr; */_IO_lock_t *_lock;
#ifdef _IO_USE_OLD_IO_FILE
};

stdout,stderr,stdin都是结构体FILE指针,所以我们可以把其指向的文件描述符打印出来:

image-20220701163305219


知道了FILE里面封装了文件描述符fd之后,我们可以理解一下C库函数fopen究竟在做什么

FILE *fopen(const char *path, const char *mode)

fopen函数在上层为用户申请一个FILE结构体变量,并返回该结构体的地址(FILE*), 在底层通过系统调用接口open打开对应的文件,得到文件描述符fd,并把这个文件描述符fd填充到FILE结构体的 _fileno变量当中,至此便完成了文件打开的工作

而C语言中的其它文件操作函数, 比如fputs,fgets等,都是先根据我们传入的文件指针找到对应的FILE结构体,然后再FILE结构体中找到文件描述符fd,最后通过文件描述符fd找到对应的文件,对文件进行一系列的操作


关于echo的重定向:

image-20220701163429505

把本来输出的显示器的内容输出到文件中, 实际上echo命令也是一个进程, 把echo进程的显示器文件stdout关闭掉(close(1)) , 再把log.txt文件打开,于是给log.txt文件分配的文件描述符就是1, echo实际就是向文件描述符为1的文件输出数据, 不关心文件描述符为1的文件是什么, 现在文件描述符为1的文件是log.txt, 于是输出的内容就被打印到log.txt中


解释输出重定向原理

关闭1, 再打开文件,给该文件分配的文件描述符就是1, printf函数是向stdout中打印,stdout的类型是FILE*类型. FILE是一个结构体,该结构体内部存储文件描述符的遍变量,与系统的1对应,而printf只关心这个整数1,printf实际上就是向文件描述符为1的文件输出数据, 并不关心文件描述符为1下标的文件是什么, 而现在我们1下标指向的是log.txt文件,所以printf就是往log.txt文件中写入


追加重定向

  • 追加重定向和输出重定向的区别:输出重定向是覆盖式的输出数据,会把原来已经有的数据覆盖掉再写进去,而追加重定向是追加式输出数据,在原来已经有的数据基础上写入数据

追加重定向与输出重定向唯一的差别就是在打开方式上,增加了 O_APPEND选项

image-20220701164454634


输入重定向

什么叫输入重定向?

把本来应该从键盘中读取内容改成从文件中读取内容

image-20220701164914837


这里以fgets函数为例子:

image-20220701164713010

从特定的文件流中按行读取内容,内容放在缓冲区s中.读取成功返回字符串的起始地址,否则返回NULL 第二个参数:缓冲区大小

image-20220701165208937

本来应该从标准输入(键盘)中获取数据,现在变成从log.txt文件获取数据

解释:

如果我们想让本应该从键盘文件读数据的scanf函数,改为从log.txt文件读取数据,我们只需要先关闭0描述符对应的文件关闭,也就是将键盘文件关闭, 后续我们打开文件log.txt ,给该文件分配的文件描述符就是0, stdin的类型是FILE*类型. FILE是一个结构体,该结构体中存储的文件描述符就是0,与系统的0对应,因此scanf实际就是向文件描述符为0的文件读取数据 而现在我们0下标指向的是log.txt文件,所就是从log.txt文件中读取数据


dup2

上述我们重定向的方法是:关闭文件然后再打开文件的方式进行重定向,但这个只是特殊情况

而更多的是:

例如:现在有两个文件描述符1 和 3被打开了,如何实现输出重定向呢?

因为在语言层调用接口的时候,函数只认数字1下标, 而不关心1下标指向的文件是什么,所以我们可以

  • 把文件描述符3中的内容拷贝到文件描述符1中,就实现了原来应该向显示器文件写入,现在往文件描述符3对应的文件写入

image-20220701171352333


dup2函数就是干这个事情的!

#include <unistd.h>
int dup2(int oldfd, int newfd);dup2()  makes  newfd  be the copy of oldfd, closing newfd first if necessary, but note thefollowing:
*  If oldfd is not a valid file descriptor, then the call fails, and newfd is not closed.
*  If oldfd is a valid file descriptor, and newfd has the same value as oldfd, then dup2()  does nothing, and returns newfd.

函数功能:dup2会把fd_array[oldfd]的内容拷贝到fd_array[newfd]当中,有必要时我们需要先关闭文件描述符为newfd的文件

  • 最终oldfd和newfd都变成oldfd的内容,可以认为把oldfd的内容覆盖原来newfd的内容

函数返回值: 如果函数调用成功,返回newfd,否则返回-1

由上述的翻译可以得出:

  • 1.如果oldfd不是有效的文件描述符,则dup2调用失败,并且此时文件描述符为newfd的文件没有被关闭
  • 2.如果oldfd是一个有效的文件描述符,但是newfd和oldfd是相同的,则dup2不做任何操作,并返回newfd

输出重定向

dup2(fd,1);//oldfd,newfd

我们把打开文件是获得的文件描述符fd和1传入dup2函数,那么dup2会把fd_array[fd]的内容拷贝到fd_array[1]中,我们向stdout输出数据,而stdout是向文件描述符为1的文件输出数据,因此,本来应该输出到显示器的数据就会重定向输出到log.txt文件当中

image-20220701205635827

选项O_TRUNC的含义:清空原来的内容再写入 O_CREAT:要打开的文件不存在就先创建,后面要自定义文件的权限

O_WRONLY : 以写的方式打开文件

  • C语言中文件操作的 "w"选项 也会先把原始文件清空,说明上层封装了这个选项

追加重定向

只需在输出只写O_WRONLY选项的基础上添加O_APPEND选项

image-20220701210004563


输入重定向

dup2(fd,0); //原本从键盘读取内容,现在从文件中读取内容

image-20220701210528921


问:执行exec* 程序替换,会影响我们曾经打开的文件嘛?

不会!因为替换的是代码和数据,并不会影响进程内核的数据结构

例子:

echo "hello Mango" > log.txt

在命令行上的重定向,会进行字符串分析, 发现>重定向符号时,会先执行dup2函数,然后进行程序替换,此时echo的内容就会重定向到指定的文件当中,程序替换并不会替换打开的文件

  • 相当于是: fork创建子进程 -> 子进程执行dup2(fd,1) ->子进程执行程序替换exec*函数

那子进程会不会和父进程共享文件描述符表呢?

会! 子进程也会形成自己的file_strcut结构体,子进程内核的数据结构task_strcut会以父进程为模板初始化自身,因此父进程和子进程的文件描述符表就是一样的,父子指向同一份文件


image-20220701215140215

父进程如果曾经打开了标准输入,标准输出,标准错误,那么子进程也会继承下去

  • 这也是为什么所有的进程都会默认打开标准输入,标准输出,标准错误,就是因为我们命令行上的进程的父进程都是bash, 也就是命令行解释器,bash需要打开标准输入进行输入指令,打开标准输出用于打印结果,打开标准错误用于提示错误信息, 创建子进程的时候,默认也继承下去了, 所以在命令行上启动的子进程最终都打开了这三个东西 (引用计数)

缓冲区

标准输出和标准错误都可以向显示器打印内容,这二者有什么区别呢?

  • 当我们重定向的时候,我们可以发现,只有标准输出的内容进行了重定向, 因为>叫做输出重定向,即把本应该显示到1号文件描述符的内容写入到指定的文件当中,而2号文件描述符并没有发生改变,仍指向标准错误

image-20220701220243345


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


那如果我们想把标准输出和标准错误的内容都重定向怎么办呢?

./可执行程序 > 文件 2>&1 表示标准错误和标准输出都进行重定向

image-20220701220359511

这样写可以理解为:

先执行前面的语句: 把1本来指向显示器的内容,变成指向特定的文件, 而后面的2>&1指的是:把1里面的内容拷贝到2, 因为1经过重定向了,指向新文件, 所以2也指向新文件

image-20220701221033523


语言级别的缓冲区

刚才我们进行重定向的时候,打开了文件却没有关闭,最后应该close(fd),

没有close(fd)的情况下 和 close(fd)的情况下对比:

image-20220702112128312


我们可以发现: close之后, C语言的写入接口,像printf,fprintf重定向后并没有被刷新出来,这是什么原因呢?


首先我们要知道缓冲区的概念, 我们之前说的缓冲区,都是指语言级别的用户级的缓冲区,也就是由C语言提供的缓冲区

C语言中的printf ,fprintf向标准输出stdout写入的时候,本质都是 写入/拷贝到C语言的缓冲区当中,然后系统会定期的把C语言缓冲区的内容拷贝到内核的缓冲区,OS再把数据更新到硬件上

而C语言缓冲区的内容写入到内核缓冲区当中,相当于把数据写入文件当中, 一定需要 fd

image-20220702113323079


那C语言提供的缓冲区又在哪呢?

前面我们知道FILE结构体当中封装了一个fd ,其实该结构体里面还 维护了与C语言缓冲区相关的内容

我们可以看一下它的源码:它是用指针来表示缓冲区的区间 (和我们vector的模拟实现相似)

//在/usr/include/libio.h
struct _IO_FILE {int _flags; /* High-order word is _IO_MAGIC; rest is flags. */
#define _IO_file_flags _flags//缓冲区相关/* The following pointers correspond to the C++ streambuf protocol. *//* Note: Tk uses the _IO_read_ptr and _IO_read_end fields directly. */char* _IO_read_ptr; /* Current read pointer */char* _IO_read_end; /* End of get area. */char* _IO_read_base; /* Start of putback+get area. */char* _IO_write_base; /* Start of put area. */char* _IO_write_ptr; /* Current put pointer. */char* _IO_write_end; /* End of put area. */char* _IO_buf_base; /* Start of reserve area. */char* _IO_buf_end; /* End of reserve area. *//* The following fields are used to support backing up and undo. */char *_IO_save_base; /* Pointer to start of non-current get area. */char *_IO_backup_base; /* Pointer to first valid character of backup area */char *_IO_save_end; /* Pointer to end of non-current get area. */struct _IO_marker *_markers;struct _IO_FILE *_chain;int _fileno; //!!!!!!!!!!!!!!!!!!封装的文件描述符!!!!!!!!!!!!!!!!!
#if 0int _blksize;
#elseint _flags2;
#endif_IO_off_t _old_offset; /* This used to be _offset but it's too small. */
#define __HAVE_COLUMN /* temporary *//* 1+column number of pbase(); 0 is unknown. */unsigned short _cur_column;signed char _vtable_offset;char _shortbuf[1];/* char* _save_gptr; char* _save_egptr; */_IO_lock_t *_lock;
#ifdef _IO_USE_OLD_IO_FILE
};

我们使用stdin/stdout/stderr 和自己打开的文件,拿到的一个文件指针FILE* ,我们的printf和fprintf都是先写到FILE*对应的FILE结构体的文件缓冲区当中, 即暂时存在FILE结构体的内部,并不会直接刷新到外设

有什么时候会把FILE结构体缓冲区的数据刷新到内核呢?

  • \n
  • 进程退出的时候

从用户级别缓冲区到内核缓冲区的刷新策略种类: (从OS->硬件同样适用)

  • 立即刷新 (不缓冲)
  • 行刷新 (行缓冲\n),比如显示器就是这种刷新策略
  • 全缓冲(缓冲区满了才刷新),比如向磁盘文件写入数据

当发生 重定向的时候 (由刷新到显示器 -> 刷新到文件当中) :隐含着刷新策略由 行缓冲 变为 全缓冲


image-20220702112128312

此时我们再来解释上面的原因: printf/fprintf进行写入,这些写入的消息都被放到用户缓冲区当中,C缓冲区可能并没有被写满,所以这部分内容并没有立即被刷新到内核当中 (全缓冲刷新策略)

  • 最后如果在进程退出之前close, 此时我们的数据还在用户级缓冲区, 因为把文件描述符关闭了,所以没有地方去刷新,因此什么也没有看到

  • 如果最后没有调close, 则在 **进程退出的时候,**把数据刷新到内核缓冲区当中,然后由OS把数据同步到硬件上,所以我们就能看到由东西输出


如果最后close,也想把数据刷新,要怎么办呢?

close之前 fflush(stdout) 强制刷新缓冲区

image-20220702152648643


总结:为什么提前关闭文件描述符发现刚刚写入的数据没了?

因为这批数据写到了用户层缓冲区即stdout所指向的FILE缓冲区当中,所以里面包含的数据并没有被立即刷新到系统层面上,当我们全部写完之后,数据都没有刷新,最后关闭文件描述符它也不可能刷新了,最终文件里面什么都没有了

写完之后,fflush强制刷新,最后关闭文件描述符这个数据就能被我们看到,根本原因就是这个数据被暂时写到了C语言的缓冲区当中

FILE结构里面包含缓冲区,这个缓冲区是用户及缓冲区,所以printf,等C语言接口,先把数据写到C语言的缓冲区,然后定期让C语言刷新到操作系统当中, 刷新的时候,要通过文件描述符,系统调用的接口,来把数据刷新到操作系统当中,如果提前关闭了文件描述符,这个数据也就不会被刷新.所以这个结果看不到


内核缓冲区

当我们刷新用户缓冲区的数据时,并不是直接把用户缓冲区的数据刷新到磁盘或者是显示器当中,而是先将数据刷新到内核缓冲区,然后再由内核缓冲区将数据刷新到磁盘或者显示器上

image-20220703093315500

最后时候没有close(1)的情况我们就不看了, 不难理解 我们来观察最后close(1)的情况:

  • 不管最后有没有close(1), 我们发现重定向之后,标准错误没有重定向,因为我们是重定向1号文件描述符向log.txt文件打印, 文件描述符2对应的-标准错误不受影响,照样向显示器写,并且刷新策略是行刷新

最后close(1)之后, 重定向后只有write写入的内容, 而printf和fprintf的内容经过重定向后都没有被写入到文件当中,这个是什么原因呢?

解析:

1)重定向时,把原本应该显示到显示器的内容显示到文件当中, 潜台词就是刷新策略从 行缓冲 变为 全缓冲, 等进程结束的时候才会把数据刷新到文件当中,而此时我们的数据还在用户级缓冲区, 因为把文件描述符关闭了,所以没有地方去刷新,因此什么也没有看到

2)write是系统调用, 没有通过C语言缓冲区进行暂存,而是直接写到内核缓冲区, 因此关闭文件描述符并不影响重定向


我们再来看下面一段代码: fork创建子进程

image-20220703094745094


当我们往显示器上打印:正常打印 当我们重定向到文件当中: 使用C语言接口的打印重复出现,而系统调用接口并不影响 这是为什么呢?

没有重定向时:

此时每条向显示器写入的信息末尾都有\n ,所以执行可执行程序./myfile向显示器打印的时候, 在fork之前,这批消息就被刷新到显示器上,所以不会打印两份

重定向时:

此时不是向显示器打印,而是写入到文件中**, 潜台词是是刷新策略变了,由行刷新变成了全缓冲** , printf/fprintf/fpus是先写到C语言缓冲区buffer当中,没有写满并不会立即刷新到内核.父进程的缓冲区也是父进程的空间,fork创建子进程,由于父子进程具有独立性,进程退出时要刷新缓冲区,刷新缓冲区的本质就是一种写入,为了维护代码数据独立性,于是就需要对数据进行写时拷贝, 父进程和子进程谁先刷新时就会发生写时拷贝, 因为父子进程都对各自缓冲区的内容刷新, 于是就可以看到文件当中库函数输出的内容有两份

为什么write没有两份呢?

因为它是系统调用接口,直接向内核缓冲区写入,不会暂存在C语言缓冲区, 这也应证了C语言缓冲区不在OS内,而是在用户层 因为如果说这个缓冲区是操作系统自带的,那么printf,fputs,write函数打印的数据重定向到文件都应该打印1次


那么如何修改可以让创建子进程,而输出的消息也只有一份呢?

在fork之前,fflush强制刷新缓冲区

image-20220703100320124

相关文章:

【Linux】重定向原理dup2缓冲区

文章目录重定向原理输出重定向关于FILE解释输出重定向原理追加重定向输入重定向dup2缓冲区语言级别的缓冲区内核缓冲区重定向原理 重定向的本质就是修改文件描述符下标对应的struct file*的内容 输出重定向 输出重定向就是把本来应该输出到显示器的数据重定向输出到另一个文…...

ROG配置ubuntu20.04.5双系统要点

win11ubuntu20.04.5 1. BIOS设置 开机长按F2进入bios设置&#xff0c;修改advanced参数&#xff1a; boot -> 关闭fast bootsecurity -> 关闭secure boot设置VMD controller为Disabled&#xff08;其他电脑是修改硬盘的SATA和ACHI模式&#xff09;。但是改了之后windo…...

机械革命旷世G16电脑开机变成绿屏了无法使用怎么办?

机械革命旷世G16电脑开机变成绿屏了无法使用怎么办&#xff1f;最近有用户使用的机械革命旷世G16电脑一开机之后&#xff0c;电脑屏幕就变成了绿色的&#xff0c;无法进行任何的操作。出现这个问题可能是因为电脑中病毒了&#xff0c;或者是系统出现故障。我们可以通过U盘来重新…...

python中关于time模块的讲解---指定格式时间字符串转为时间戳

本文章可以解决任意字符串格式时间转为时间戳 返回json格式 可以在此基础上进行修改 时间格式控制符 说明 %Y 四位数的年份&#xff0c;取值范围为0001~9999,如1900 %m 月份&#xff08;01~12&#xff09;&#xff0c;例如10 %d 月中的一天&#xff08;01~31&#xff09;例…...

MySql存储引擎与索引

MySql引擎 存储引擎是具体操作数据的地方&#xff0c;是一种对数据存储的技术与其配套的功能 不同存储引擎所采用存储的方式的不同&#xff0c;并且索引技巧与锁定水平也不同 根据业务的需求灵活的选择存储引擎即可满足的实际的需要 Innodb Innodb是MySql中的默认安装的引擎…...

typing库

typing 库 引入 在日常代码编写中&#xff0c;由于python语言特性&#xff0c;不用像go等编译性语言一样&#xff0c;在定义函数时就规范参数和放回值的类型。 def demo(a, b):return "ab" 此时 a 和 b 可以传入任意类型参数毫无疑问&#xff0c;这一特性&#…...

linux shell 入门学习笔记10内置shell命令

bash基础的内置命令 echoevalexecexportreadshift echo命令 -n 不换行输出 -e 解析字符串中的特殊符号\n 换行 \r 回车 \t 制表符 四个空格 \b 退格-n参数演示 xiao123xiao123:~/Downloads$ echo 你真胖;echo 你还挺可爱; 你真胖 你还挺可爱 xiao123xiao123:~/Downloads$ ec…...

[动手写操作系统]-02-开机运行系统并打印‘hello‘

文章目录 理解三个概念: 中断interrupts, CPU,寄存器registers 目标:让上一个静默的界面打印一些文本 我们将改进我们的无限循环引导扇区并在屏幕上打印一些东西。我们将为此提出中断。 我们尝试将"Hello"写到寄存器al, 字节0x0e写到ah (the higher part of ax),并…...

Delete `␍`eslint(prettier/prettier) in vscode 的解决方案

错误描述从 Github 仓库拉取代码&#xff0c;使用 vscode 打开&#xff0c;页面报错&#xff0c;每一行都爆红 &#xff08;如下图&#xff09;问题原因由于历史原因&#xff0c;windows下和linux下的文本文件的换行符不一致。Windows在换行的时候&#xff0c;使用了换行符CRLF…...

gof23 设计模式 各个模式代码demo

Gof23 设计模式&#xff0c;也叫Gang of Four&#xff08;GoF&#xff09;设计模式&#xff0c;是由四位设计模式大师&#xff08;Erich Gamma、Richard Helm、Ralph Johnson 和 John Vlissides&#xff09;撰写的一本书——《设计模式&#xff1a;可复用面向对象软件的基础》所…...

0 初识Kotlin

0 基本介绍 相信很多开发者对Kotlin还是比较陌生的。 Kotlin是一种新型的编程语言&#xff0c;由JetBrains公司开发与设计&#xff0c;在2012年开源&#xff0c; 但没引起什么注意。 直到2017年google宣布将Kotlin作为Android开发的首选语言&#xff0c;Kotlin才开始大放异彩。…...

阿里云服务器部署SpringBoot+Vue项目(宝塔面板傻瓜式操作)

准备工作 一台服务器(我用的是阿里云)SpringBoot项目的jar包Vue项目的dist包 一、购买服务器 然后重置实例密码。 远程连接 登陆成功后安装宝塔面板 二、安装宝塔面板(无账号的注册一个账号) 地址&#xff1a;https://www.bt.cn/new/download.html 选择对应的镜像、不知道…...

27. 移除元素 26. 删除有序数组中的重复项 88. 合并两个有序数组(双指针遍历)

目录[27. 移除元素-力扣](https://leetcode.cn/problems/remove-element/description/?languageTagsc)[26. 删除有序数组中的重复项](https://leetcode.cn/problems/remove-duplicates-from-sorted-array/)[88. 合并两个有序数组](https://leetcode.cn/problems/merge-sorted-…...

什么时候用std::move()?

文章目录1. "是什么?"2. "有何用?"3. "什么时候用?"1. “是什么?” 虽然 std::move() 从技术角度上是一个函数 &#xff0c;但我认为它不是真正的函数。 它是编译器考虑表达式值的方式之间的转换器。 2. “有何用?” 首先要注意的是 std…...

建立做机器学习项目的范式

建立起做机器学习项目的范式&#xff0c;萃取出核心步骤&#xff0c;避免后面做项目没有明确的方向。 核心步骤&#xff1a; 1、明确自己想做什么样的项目&#xff0c;感兴趣的领域&#xff1b; 2、找到满足项目的数据集&#xff0c;开源的或者自建数据集&#xff1b; 数据…...

搭建k8s高可用集群—20230225

文章目录多master&#xff08;高可用&#xff09;介绍高可用集群使用技术介绍搭建高可用k8s集群步骤1. 准备环境-系统初始化2. 在所有master节点上部署keepalived3.1 安装相关包3.2 配置master节点3.3 部署haproxy错误解决3. 所有节点安装Docker/kubeadm/kubelet4. 部署Kuberne…...

Java 修饰符和多态

文章目录一、修饰符1. 权限修饰符2. 状态修饰符2.1 final2.2 static二、多态1. 成员访问特点2. 多态中的转型3. 多态案例一、修饰符 1. 权限修饰符 2. 状态修饰符 2.1 final final 关键字是最终的意思&#xff0c;可以修饰成员方法、成员变量及类。 //1.修饰成员变量 publi…...

学了一年Java的我,想转嵌入式了

秋名山码民的主页 &#x1f389;欢迎关注&#x1f50e;点赞&#x1f44d;收藏⭐️留言&#x1f4dd; &#x1f64f;作者水平有限&#xff0c;如发现错误&#xff0c;还请私信或者评论区留言&#xff01; 目录前言为啥我想去转行&#xff1f;如果我现在选择转硬件&#xff0c;我…...

【Git】Git冲突与解决方法

目录 一、Git冲突如何产生&#xff1f; 二、解决Git冲突—手动修改冲突 【第一步】在 hot-fix 分支上增加如下代码&#xff0c;并且提交。 【第二步】在master 分支上同样的地方增加如下代码&#xff0c;并且提交。 【第三步】 我们现在在 master 分支上合并 hot-fix 分支&a…...

深度剖析数据在内存的存储

目录1.深度剖析数据在内存的存储(前言)数据类型介绍类型的基本归类整形在内存中的存储原码、反码、补码大小端练习总结1.深度剖析数据在内存的存储(前言) 今天就让我戴佳伟给大家讲一下数据在内存中的存储。之中有好多让我们深思的点&#xff0c;大家都拿起笔记本&#xff0c;…...

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周&#xff0c;有很多同学在写期末Java web作业时&#xff0c;运行tomcat出现乱码问题&#xff0c;经过多次解决与研究&#xff0c;我做了如下整理&#xff1a; 原因&#xff1a; IDEA本身编码与tomcat的编码与Windows编码不同导致&#xff0c;Windows 系统控制台…...

Redis相关知识总结(缓存雪崩,缓存穿透,缓存击穿,Redis实现分布式锁,如何保持数据库和缓存一致)

文章目录 1.什么是Redis&#xff1f;2.为什么要使用redis作为mysql的缓存&#xff1f;3.什么是缓存雪崩、缓存穿透、缓存击穿&#xff1f;3.1缓存雪崩3.1.1 大量缓存同时过期3.1.2 Redis宕机 3.2 缓存击穿3.3 缓存穿透3.4 总结 4. 数据库和缓存如何保持一致性5. Redis实现分布式…...

鸿蒙DevEco Studio HarmonyOS 5跑酷小游戏实现指南

1. 项目概述 本跑酷小游戏基于鸿蒙HarmonyOS 5开发&#xff0c;使用DevEco Studio作为开发工具&#xff0c;采用Java语言实现&#xff0c;包含角色控制、障碍物生成和分数计算系统。 2. 项目结构 /src/main/java/com/example/runner/├── MainAbilitySlice.java // 主界…...

SiFli 52把Imagie图片,Font字体资源放在指定位置,编译成指定img.bin和font.bin的问题

分区配置 (ptab.json) img 属性介绍&#xff1a; img 属性指定分区存放的 image 名称&#xff0c;指定的 image 名称必须是当前工程生成的 binary 。 如果 binary 有多个文件&#xff0c;则以 proj_name:binary_name 格式指定文件名&#xff0c; proj_name 为工程 名&…...

CRMEB 中 PHP 短信扩展开发:涵盖一号通、阿里云、腾讯云、创蓝

目前已有一号通短信、阿里云短信、腾讯云短信扩展 扩展入口文件 文件目录 crmeb\services\sms\Sms.php 默认驱动类型为&#xff1a;一号通 namespace crmeb\services\sms;use crmeb\basic\BaseManager; use crmeb\services\AccessTokenServeService; use crmeb\services\sms\…...

从面试角度回答Android中ContentProvider启动原理

Android中ContentProvider原理的面试角度解析&#xff0c;分为​​已启动​​和​​未启动​​两种场景&#xff1a; 一、ContentProvider已启动的情况 1. ​​核心流程​​ ​​触发条件​​&#xff1a;当其他组件&#xff08;如Activity、Service&#xff09;通过ContentR…...

前端中slice和splic的区别

1. slice slice 用于从数组中提取一部分元素&#xff0c;返回一个新的数组。 特点&#xff1a; 不修改原数组&#xff1a;slice 不会改变原数组&#xff0c;而是返回一个新的数组。提取数组的部分&#xff1a;slice 会根据指定的开始索引和结束索引提取数组的一部分。不包含…...

Python实现简单音频数据压缩与解压算法

Python实现简单音频数据压缩与解压算法 引言 在音频数据处理中&#xff0c;压缩算法是降低存储成本和传输效率的关键技术。Python作为一门灵活且功能强大的编程语言&#xff0c;提供了丰富的库和工具来实现音频数据的压缩与解压。本文将通过一个简单的音频数据压缩与解压算法…...

leetcode_69.x的平方根

题目如下 &#xff1a; 看到题 &#xff0c;我们最原始的想法就是暴力解决: for(long long i 0;i<INT_MAX;i){if(i*ix){return i;}else if((i*i>x)&&((i-1)*(i-1)<x)){return i-1;}}我们直接开始遍历&#xff0c;我们是整数的平方根&#xff0c;所以我们分两…...

【Ftrace 专栏】Ftrace 参考博文

ftrace、perf、bcc、bpftrace、ply、simple_perf的使用Ftrace 基本用法Linux 利用 ftrace 分析内核调用如何利用ftrace精确跟踪特定进程调度信息使用 ftrace 进行追踪延迟Linux-培训笔记-ftracehttps://www.kernel.org/doc/html/v4.18/trace/events.htmlhttps://blog.csdn.net/…...