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

Linux中输入和输出基本过程

1.文件内核级缓冲区

前面在如何理解Linux一切皆文件的特点中提到为了保证在Linux中所有进程访问文件时的方式趋近相 同,在f ile 结构体中存在一个 files_operations 结构体指针,对应的结构体保存所有文件操作的函 数指针(这个结构体也被称为操作表)

每一个f ile 结构体中除了有自己的操作表以外还有一个文件的内核级缓冲区,这个缓冲区不同于语言层 面的缓冲区,在调用底层系统接口的读或者写时,会有一方先将内容保存到该缓冲区,再将内容移动到 指定设备

例如,对于读函数 read 来说,以从磁盘文件读取文件内容为例,首先操作系统会从磁盘中读取文件内容 到缓冲区,再由 read 函数从缓冲区将内容读取到指定的设备;对于 将内存中需要写入的内容先写入缓冲区,再由 write 函数来说,首先操作系统会 write 函数从缓冲区写入到磁盘中。除了前面提到的两个 单一过程外,还要一种复合过程:对文件的内容进行修改。这一种过程既涉及到读取,也涉及到写入, 所以首先需要通过操作系统读入需要修改的内容到内核级缓冲区,由 read 函数将缓冲区中的数据读到内 存,在程序运行中对读取到的内容进行修改,再通过 write 函数将修改后的内容写入到缓冲区,最后由 操作系统从缓冲区写入到磁盘

如果抽象化一下 read 函数和 write 函数的过程可以发现这两个函数的基本行为就是读写缓冲区,所以 这两个函数也可以理解为拷贝函数, read 函数即为将缓冲区中的数据拷贝到内存中的指定位置, write 函数即为将内存中的数据拷贝到缓冲区

上面整个过程中, read 函数和 write 函数只完成对缓冲区中的数据进行处理,但是缓冲区中的数据何 时移动到指定的设备由操作系统自主决定

如果用户向自主决定何时将内核级缓冲区中的数据刷新到内核级缓冲区可以使用 fsync函数,其原型如下:

int fsync(int fd);

读或者写过程示意图如下:

2.何为重定向

前面提到,文件描述符是Linux中每一个文件的唯一标识符,也就是说,通过文件描述符可以唯一确定一 个文件,而stdin、stdout和stderr是每一个C语言程序默认打开的三个文件,对应的文件描述符 为0、1和2,而之所以文件描述符是从0开始,本质是因为文件描述符是fd_array数组的下标,当用户 再打开一个文件时,对应的文件结构指针就会存储到fd_array的指定位置,而因为下标0、1和2已经被 占用,所以新开的文件对应的下标只能从3开始

现在关闭0号位置的文件,观察效果,例如下面的代码:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>int main()
{close(0);int fd1 = open("test1.txt", O_WRONLY | O_TRUNC | O_CREAT);int fd2 = open("test2.txt", O_WRONLY | O_TRUNC | O_CREAT);int fd3 = open("test3.txt", O_WRONLY | O_TRUNC | O_CREAT);int fd4 = open("test4.txt", O_WRONLY | O_TRUNC | O_CREAT);printf("%d\n", fd1);printf("%d\n", fd2);printf("%d\n", fd3);printf("%d\n", fd4);close(fd1);close(fd2);close(fd3);close(fd4);return 0;
}

如果关闭的是2号文件,观察效果,例如下面的代码:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>int main()
{close(2);int fd1 = open("test1.txt", O_WRONLY | O_TRUNC | O_CREAT);int fd2 = open("test2.txt", O_WRONLY | O_TRUNC | O_CREAT);int fd3 = open("test3.txt", O_WRONLY | O_TRUNC | O_CREAT);int fd4 = open("test4.txt", O_WRONLY | O_TRUNC | O_CREAT);printf("%d\n", fd1);printf("%d\n", fd2);printf("%d\n", fd3);printf("%d\n", fd4);close(fd1);close(fd2);close(fd3);close(fd4);return 0;
}

运行:

从上面的代码中可以看出,在Linux中,一个文件被打开时,文件描述符的分配原则是在 fd_array 中找 到最小的且没有被其他 file 结构指针占用的位置

以关闭0号位置为例,示意图如下:

在上面的演示中,先关闭了某一个文件描述符较前的文件,再打开另一个文件,打开的这个文件所处的 位置是就是被关闭的那个文件的位置,此时再使用输出语句输出内容,原本应该输出到文件描述符较前 的原始文件中,比如前面的 stdin ,后面却输出到了文件中 test1.txt ,这个过程就称为文件重定 向,主要原理就是文件描述符是固定不变的,而输出和输入只认文件描述符,不会在意这个文件描述符 对应的位置指向的是哪一个文件

在Linux中,存在一个系统调用接口使得可以在程序中实现重定向,这个函数为dup2,其原型如下:

int dup2(int oldfd, int newfd);

在Linux操作手册中, dup2 函数的描述如下:

dup2() makes newfd be the copy of oldfd, closing newfd first if necessary

参数解释:

  1. oldfd:该参数表示待拷贝的文件的文件指针对应的文件描述符
  2. newfd:该参数表示被覆盖的文件的文件指针对应的文件描述符

示意图如下:

所以,使用dup2就可以实现使用printf函数本应该输出到stdout中,而输出到test1.txt的效 果,代码如下:

#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>int main()
{int fd1 = open("test1.txt", O_WRONLY | O_TRUNC | O_CREAT, 0666);int fd2 = open("test2.txt", O_WRONLY | O_TRUNC | O_CREAT, 0666);int fd3 = open("test3.txt", O_WRONLY | O_TRUNC | O_CREAT, 0666);int fd4 = open("test4.txt", O_WRONLY | O_TRUNC | O_CREAT, 0666);dup2(fd1, 1);printf("%d\n", fd1);printf("%d\n", fd2);printf("%d\n", fd3);printf("%d\n", fd4);close(fd1);close(fd2);close(fd3);close(fd4);return 0;
}

需要注意,因为在使用 dup2 函数之前, stdout 已经被打开了,此时 open 函数打开 时就只能使用3号下标的位置,所以可以看到 test1.txt 文件 dup2 函数的确实现了将内容输出到 test1.txt 文件而不 是st dout 中,此时示意图如下:

这里需要注意一个细节:尽管 dup2 函数会关闭被覆盖的文件 test1.txt 占用了被覆盖的文件 stdout ,但是关闭后被拷贝的文件 stdout 的位置,所以再打开其他文件依旧会从7号位置开始,例如下 面的代码演示:

#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>int main()
{int fd1 = open("test1.txt", O_WRONLY | O_TRUNC | O_CREAT, 0666);int fd2 = open("test2.txt", O_WRONLY | O_TRUNC | O_CREAT, 0666);int fd3 = open("test3.txt", O_WRONLY | O_TRUNC | O_CREAT, 0666);int fd4 = open("test4.txt", O_WRONLY | O_TRUNC | O_CREAT, 0666);dup2(fd1, 1);int fd5 = open("test4.txt", O_WRONLY | O_TRUNC | O_CREAT, 0666); // 重定向后打开一个新文件printf("%d\n", fd1);printf("%d\n", fd2);printf("%d\n", fd3);printf("%d\n", fd4);printf("%d\n", fd5);close(fd1);close(fd2);close(fd3);close(fd4);close(fd5);return 0;
}

但是,前面的代码中,只演示了关闭0号位置和2号位置的文件,如果此时关闭1号位置的文件,再打开同 样的四个文件,输出每一个文件的文件描述符,从前面的规律可以推出,输出语句会因为1号位置的文件 是test1.txt而将内容输出到test1.txt中,例如下面的代码:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>int main()
{close(1);int fd1 = open("test1.txt", O_WRONLY | O_TRUNC | O_CREAT, 0666);int fd2 = open("test2.txt", O_WRONLY | O_TRUNC | O_CREAT, 0666);int fd3 = open("test3.txt", O_WRONLY | O_TRUNC | O_CREAT, 0666);int fd4 = open("test4.txt", O_WRONLY | O_TRUNC | O_CREAT, 0666);printf("%d\n", fd1);printf("%d\n", fd2);printf("%d\n", fd3);printf("%d\n", fd4);close(fd1);close(fd2);close(fd3);close(fd4);return 0;
}

编译运行上面的代码后可以看到不论是test1.txt还是其他文件都没有显示需要的内容,控制台也没有 正常打印需要的内容

但是如果将代码修改为如下:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>int main()
{// ...fflush(stdout);close(fd1);close(fd2);close(fd3);close(fd4);return 0;
}

编译运行上面的代码后可以看到结果如下:

现在就引入了一个问题,为什么加了fflush(stdout)就可以看到需要的效果

前面提到,在调用操作系统接口中的读写函数时会涉及到一个文件内核级缓冲区,这个缓冲区是为了减 少操作系统进行IO操作时产生的时间和空间的消耗,但是如果用户使用的是语言级别的接口,例如 fread或者fwrite等,那么此时就会出现用户的接口到操作系统的消耗,这个消耗主要来自于语言级 函数多次调用系统接口时创建函数栈帧,所以为了减少这种情况下的时间和空间消耗,就存在了语言级 别的缓冲区

但是,在实现进度条时提到了\n可以刷新语言级别的缓冲区,此处为什么用了\n也没有刷新,原因就 在于语言级别的缓冲区刷新情况有三种:

  1. 行刷新,主要是stdout文件时的刷新
  2. 满刷新,当语言级别的缓冲区写满时刷新
  3. 不缓冲

而此处的\n就属于行刷新,但是此时的printf认识的fd为1的文件并不是stdout,所以行刷新就 失效了,转换成默认的满刷新,所以需要调用fflush(stdout)将当前语言级别缓冲区中的数据调用写 函数刷新到操作系统的内核级缓冲区,再由操作系统自主刷新到输出设备中

如果将前面的代码修改为如下,观察效果:

#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>int main()
{close(1);int fd1 = open("test1.txt", O_WRONLY | O_TRUNC | O_CREAT, 0666);int fd2 = open("test2.txt", O_WRONLY | O_TRUNC | O_CREAT, 0666);int fd3 = open("test3.txt", O_WRONLY | O_TRUNC | O_CREAT, 0666);int fd4 = open("test4.txt", O_WRONLY | O_TRUNC | O_CREAT, 0666);printf("%d\n", fd1);printf("%d\n", fd2);printf("%d\n", fd3);printf("%d\n", fd4);return 0;
}

编译运行上面的代码后可以看到结果如下:

可以看到此时尽管没有fflush(stdout)也可以正常将内容输出到test1.txt,主要原因是当程序即 将结束时,会进行缓冲区自动刷新,相当于自动进行了一次fflush(stdout),而前面调用 close(fd)时之所以没有刷新缓冲区是因为系统内部的文件已经被关闭,语言级的缓冲区无法将内容通 过系统调用刷新到系统内核级缓冲区

所以,由上面的结果可以推出,在C语言中,文件结构FILE肯定包含文件描述符和缓冲区,而C语言的 所有输入输出函数本质也是拷贝函数,只是源头或者目标是其结构体中的缓冲区,对应的源码如下:

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
};

3.子进程与缓冲区

前面演示的都是只有一个进程打开关闭文件,如果此时在自动刷新语言级别的缓冲区之前创建了一个子 进程,观察下面代码的执行效果:

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>int main()
{int fd = open("log.txt", O_CREAT | O_WRONLY | O_APPEND, 0666);dup2(fd, stdout->_fileno);// C库函数printf(" hello printf\n");fprintf(stdout, " hello fprintf\n");const char *message = " hello fwrite\n";fwrite(message, 1, strlen(message), stdout);// 系统调用const char *w = " hello write\n";write(1, w, strlen(w));// 创建子进程fork();return 0;
}

查看 log.txt 的内容

可以看到,除了系统调用接口 write 函数以外,其他的C语言库函数均出现两次打印的情况,本质就是 因为语言级缓冲区自动刷新到系统内核级缓冲区机制,而因为 fork 创建了子进程,所以子进程在不修改 的情况下会共享父进程中的所有内容,包括语言级缓冲区,所以在最后程序结束时,因为父进程没有刷 新语言级缓冲区,所以创建子进程之后,父子进程都要进行一次刷新操作,所以父子进程都通过系统调 用接口将数据写入到内核级缓冲区中,而之所以 write 函数没有写入两次,就是因为父进程已经调用完 成write函数了,系统内核级缓冲区已经有对应的内容,所以此时子进程就不需要再调用了,最后由操 作系统决定将所有内容刷新到文件中

相关文章:

Linux中输入和输出基本过程

1.文件内核级缓冲区 前面在如何理解Linux一切皆文件的特点中提到为了保证在Linux中所有进程访问文件时的方式趋近相 同&#xff0c;在f ile 结构体中存在一个 files_operations 结构体指针&#xff0c;对应的结构体保存所有文件操作的函 数指针&#xff08;这个结构体也被称为…...

使用 acme.sh 签发和自动续期 ssl https 证书

acme.sh 是一个热度非常高的签发和自动续期 https 证书的工具&#xff0c;虽然官网上提供了充分的操作说明&#xff0c;但是不够简洁&#xff0c;本文以在 nginx 中签发和配置http 为例&#xff0c;列出必要的几个简单步骤。 安装 因为网络原因&#xff0c;github 大部分人是…...

spring重点面试题总结

bean的生命周期 在 Spring 中&#xff0c;BeanDefinition、Bean 实例化、依赖注入、Aware 接口的处理、以及 BeanPostProcessor 的前置和后置处理等&#xff0c;都是 Spring 容器管理 Bean 生命周期的关键部分。下面我将详细解释这些过程。 1. 通过 BeanDefinition 获取 Bean…...

新的一章:codegeex

三层结构的优点&#xff1a;可扩展性&#xff0c;可复用性...

游戏引擎学习第50天

仓库: https://gitee.com/mrxiao_com/2d_game Minkowski 这个算法有点懵逼 回顾 基本上&#xff0c;现在我们所处的阶段是&#xff0c;回顾最初的代码&#xff0c;我们正在讨论我们希望在引擎中实现的所有功能。我们正在做的版本是初步的、粗略的版本&#xff0c;涵盖我们认…...

快速理解类的加载过程

当程序主动使用某个类时&#xff0c;如果该类还未加载到内存中&#xff0c;则系统会通过如下三个步骤来对该类进行初始化&#xff1a; 1.加载&#xff1a;将class文件字节码内容加载到内存中&#xff0c;并将这些静态数据转换成方法区的运行时数据结构&#xff0c;然后生成一个…...

医院跌倒检测识别 使用YOLO,COCO ,VOC格式对4806张原始图片进行标注,可识别病人跌倒,病人的危险行为,病床等场景,预测准确率可达96.7%

医院跌倒检测识别 使用YOLO,COCO ,VOC格式对4806张原始图片进行标注&#xff0c;可识别病人跌倒&#xff0c;病人的危险行为&#xff0c;病床等场景&#xff0c;预测准确率可达96.7&#xff05; 数据集分割 4806总图像数 训练组70&#xff05; 3364图片 有效集20&#…...

[Unity Shader] 【游戏开发】【图形渲染】Unity Shader的种类2-顶点/片元着色器与固定函数着色器的选择与应用

Unity 提供了不同种类的 Shader,每种 Shader 有其独特的优势和适用场景。在所有类型的 Shader 中,顶点/片元着色器(Vertex/Fragment Shader)与固定函数着色器(Fixed Function Shader)是两种重要的着色器类型。尽管它们具有不同的编写方式和用途,理解其差异与应用场景,对…...

浏览器端的 js 包括哪几个部分

一、核心语言部分 1. 变量与数据类型 变量用于存储数据&#xff0c;在 JavaScript 中有多种数据类型&#xff0c;如基本数据类型&#xff08;字符串、数字、布尔值、undefined、null&#xff09;和引用数据类型&#xff08;对象、数组、函数&#xff09;。 let name "…...

GoogLeNet网络:深度学习领域的创新之作

目录 ​编辑 引言 GoogLeNet的核心创新&#xff1a;Inception模块 Inception模块的工作原理 1x1卷积&#xff1a;降维与减少计算量 1x1卷积的优势 深度分离卷积&#xff1a;计算效率的提升 深度分离卷积的实现 全局平均池化&#xff1a;简化网络结构 全局平均池化的作…...

深入C语言文件操作:从库函数到系统调用

引言 文件操作是编程中不可或缺的一部分&#xff0c;尤其在C语言中&#xff0c;文件操作不仅是处理数据的基本手段&#xff0c;也是连接程序与外部世界的重要桥梁。C语言提供了丰富的库函数来处理文件&#xff0c;如 fopen、fclose、fread、fwrite 等。然而&#xff0c;这些库…...

Java序列化

Java序列化 简单来说&#xff1a; 序列化是将对象的状态信息转换为可以存储或传输的形式&#xff08;如字节序列&#xff09;的过程。在 Java 中&#xff0c;通过序列化可以把一个对象保存到文件、通过网络传输到其他地方或者存储到数据库等。最直接的原因就是某些场景下需要…...

基坑表面位移沉降倾斜自动化监测 非接触式一体化解决机器视觉

基于变焦视觉位移监测仪的基坑自动化监测新方案是一种集成了光学、机械、电子、边缘计算、AI识别以及云平台软件等技术的自动化系统。该方案利用变焦机器视觉原理&#xff0c;结合特殊波段成像识别技术和无源靶标&#xff0c;实现了非接触式大空间、多断面、多测点的高精度水平…...

提升效率:精通Windows命令行的艺术

文章目录 引言1. 基本目录操作命令dir&#xff1a;列出目录内容cd&#xff1a;更改目录mkdir 和 rmdir&#xff1a;创建和删除目录 2. 文件操作命令copy&#xff1a;复制文件或目录move&#xff1a;移动或重命名文件/目录del&#xff1a;删除文件 3. 文件查看命令type&#xff…...

ESP32-S3-devKitC-1 点亮板上的WS2812 RGB LED

ESP32-S3-devKitC-1 板上自带了一个RGB LED&#xff0c;型号为 WS2812。 RGB LED 在板上的位置如下图所示。 为了点亮这个WS2812&#xff0c;需要确定这颗RGB LED连接到哪个GPIO上了。 下面是确定GPIO管脚的过程&#xff1a; 1、根据原理图 2、根据PCB布局图&#xff1a; 程…...

python调用matlab函数(内置 + 自定义) —— 安装matlab.engine

文章目录 一、简介二、安装matlab.engine2.1、基于 CMD 安装2.2、基于 MATLAB 安装&#xff08;不建议&#xff09; 三、python调用matlab函数&#xff08;内置 自定义&#xff09; 一、简介 matlab.engine&#xff08;MATLAB Engine API for Python&#xff09;&#xff1a;…...

CAD c# 生成略缩图预览

代码如下&#xff1a; using (Transaction tr currentdb.TransactionManager.StartTransaction()){//当前数据库开启事务using (Database tempdb new Database(false, true)) //创建临时数据库(两个参数&#xff1a;是否创建符号表&#xff0c;不与当前文档关联){try{Bitmap …...

端点鉴别、安全电子邮件、TLS

文章目录 端点鉴别鉴别协议ap 1.0——发送者直接发送一个报文表明身份鉴别协议ap 2.0——ap1.0 的基础上&#xff0c;接收者对报文的来源IP地址进行鉴别鉴别协议ap 3.0——使用秘密口令&#xff0c;口令为鉴别者和被鉴别者之间共享的秘密鉴别协议ap 3.1——对秘密口令进行加密&…...

汽车电子元件的可靠性保障:AEC-Q102认证

AEC-Q102标准的起源与价值 随着汽车电子系统的日益复杂&#xff0c;电子器件必须能够在极端的温度、湿度、振动和电磁干扰等恶劣条件下保持性能。AEC-Q102标准由汽车电子委员会&#xff08;AEC&#xff09;制定&#xff0c;专门针对LED、激光二极管和光电二极管等光电器件&…...

主成分分析法大全(包括stata+matlab)

数据简介&#xff1a;主成分分析&#xff08;Principal Component Analysis&#xff0c;PCA&#xff09;&#xff0c; 是一种统计方法。通过正交变换将一组可能存在相关性的变量转换为一组线性不相关的变量&#xff0c;转换后的这组变量叫主成分。在实际课题中&#xff0c;为了…...

云原生核心技术 (7/12): K8s 核心概念白话解读(上):Pod 和 Deployment 究竟是什么?

大家好&#xff0c;欢迎来到《云原生核心技术》系列的第七篇&#xff01; 在上一篇&#xff0c;我们成功地使用 Minikube 或 kind 在自己的电脑上搭建起了一个迷你但功能完备的 Kubernetes 集群。现在&#xff0c;我们就像一个拥有了一块崭新数字土地的农场主&#xff0c;是时…...

中南大学无人机智能体的全面评估!BEDI:用于评估无人机上具身智能体的综合性基准测试

作者&#xff1a;Mingning Guo, Mengwei Wu, Jiarun He, Shaoxian Li, Haifeng Li, Chao Tao单位&#xff1a;中南大学地球科学与信息物理学院论文标题&#xff1a;BEDI: A Comprehensive Benchmark for Evaluating Embodied Agents on UAVs论文链接&#xff1a;https://arxiv.…...

Leetcode 3577. Count the Number of Computer Unlocking Permutations

Leetcode 3577. Count the Number of Computer Unlocking Permutations 1. 解题思路2. 代码实现 题目链接&#xff1a;3577. Count the Number of Computer Unlocking Permutations 1. 解题思路 这一题其实就是一个脑筋急转弯&#xff0c;要想要能够将所有的电脑解锁&#x…...

【C++从零实现Json-Rpc框架】第六弹 —— 服务端模块划分

一、项目背景回顾 前五弹完成了Json-Rpc协议解析、请求处理、客户端调用等基础模块搭建。 本弹重点聚焦于服务端的模块划分与架构设计&#xff0c;提升代码结构的可维护性与扩展性。 二、服务端模块设计目标 高内聚低耦合&#xff1a;各模块职责清晰&#xff0c;便于独立开发…...

聊一聊接口测试的意义有哪些?

目录 一、隔离性 & 早期测试 二、保障系统集成质量 三、验证业务逻辑的核心层 四、提升测试效率与覆盖度 五、系统稳定性的守护者 六、驱动团队协作与契约管理 七、性能与扩展性的前置评估 八、持续交付的核心支撑 接口测试的意义可以从四个维度展开&#xff0c;首…...

【HarmonyOS 5 开发速记】如何获取用户信息(头像/昵称/手机号)

1.获取 authorizationCode&#xff1a; 2.利用 authorizationCode 获取 accessToken&#xff1a;文档中心 3.获取手机&#xff1a;文档中心 4.获取昵称头像&#xff1a;文档中心 首先创建 request 若要获取手机号&#xff0c;scope必填 phone&#xff0c;permissions 必填 …...

【Oracle】分区表

个人主页&#xff1a;Guiat 归属专栏&#xff1a;Oracle 文章目录 1. 分区表基础概述1.1 分区表的概念与优势1.2 分区类型概览1.3 分区表的工作原理 2. 范围分区 (RANGE Partitioning)2.1 基础范围分区2.1.1 按日期范围分区2.1.2 按数值范围分区 2.2 间隔分区 (INTERVAL Partit…...

企业如何增强终端安全?

在数字化转型加速的今天&#xff0c;企业的业务运行越来越依赖于终端设备。从员工的笔记本电脑、智能手机&#xff0c;到工厂里的物联网设备、智能传感器&#xff0c;这些终端构成了企业与外部世界连接的 “神经末梢”。然而&#xff0c;随着远程办公的常态化和设备接入的爆炸式…...

PHP 8.5 即将发布:管道操作符、强力调试

前不久&#xff0c;PHP宣布了即将在 2025 年 11 月 20 日 正式发布的 PHP 8.5&#xff01;作为 PHP 语言的又一次重要迭代&#xff0c;PHP 8.5 承诺带来一系列旨在提升代码可读性、健壮性以及开发者效率的改进。而更令人兴奋的是&#xff0c;借助强大的本地开发环境 ServBay&am…...

Leetcode33( 搜索旋转排序数组)

题目表述 整数数组 nums 按升序排列&#xff0c;数组中的值 互不相同 。 在传递给函数之前&#xff0c;nums 在预先未知的某个下标 k&#xff08;0 < k < nums.length&#xff09;上进行了 旋转&#xff0c;使数组变为 [nums[k], nums[k1], …, nums[n-1], nums[0], nu…...