[Linux]:文件(下)
✨✨ 欢迎大家来到贝蒂大讲堂✨✨
🎈🎈养成好习惯,先赞后看哦~🎈🎈
所属专栏:Linux学习
贝蒂的主页:Betty’s blog
1. 重定向原理
在明确了文件描述符的概念及其分配规则后,我们就可以解释我们之前所说的重定向的原理。
1.1 输出重定向
输出重定向的本质就是,将我们本应该输出到一个文件的数据重定向输出到另一个文件中,即关闭对应标准输出流的文件描述符1,然后让该文件描述符重新指向新的文件,最后如果我们再对该文件描述符进行写入,本应该打印在屏幕的数据就重定向进入新文件。
同样该操作我们也可以通过代码实现:
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
int main()
{close(1);//关闭标准输出流int fd=open("log.txt",O_WRONLY|O_CREAT,0666);if(fd<0){perror("open fail:");return 1;}//向屏幕打印信息printf("hello betty!\n");printf("hello betty!\n");printf("hello betty!\n");printf("hello betty!\n");printf("hello betty!\n");fflush(stdout);//刷新缓冲区close(fd);return 0;
}
从上述输出我们发现,本应该向屏幕打印的数据,结果通过输出重定向打印进了log.txt
文件。
其中关闭文件之前我们必须刷新缓冲区,至于为什么,我们在后面讲解缓冲区时专门讲解。
1.2 输入重定向
输入重定向的本质也是与输出重定向同理,将我们本应该输入到一个文件的数据重定向输入到另一个文件中,即关闭对应标准输出流的文件描述符0,然后让该文件描述符重新指向新的文件,最后如果我们再对该文件描述符进行读取,本应该从键盘读取的数据就重定向变为从新文件读取。
同样该操作我们也可以通过代码实现:
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
int main()
{close(0);//关闭标准输入流int fd=open("log.txt",O_RDONLY);if(fd<0){perror("open fail:");return 1;}//向屏幕打印信息char buf[128]={'\0'};while (scanf("%s", buf) != EOF){printf("%s\n", buf);}close(fd);return 0;
}
从上述输出我们发现,本应该向屏幕读取数据,结果通过输入重定向从log.txt
文件读取。
1.3 追加重定向
追加重定向本质就简单的多,只需要写入文件时加入O_APPEND
选项即可。
int fd=open("log.txt",O_WRONLY|O_APPEND|O_CREAT,0666);
然后我们可能疑惑的是,标准输出流与标准错误流对应的设备都是显示器,那么这两者之间有什么区别呢?
我们可以先看一下这段代码:
#include<stdio.h>
int main()
{printf("stdout:hello printf!\n");perror("stderr:hello perror!");fprintf(stdout,"stdout:hello fprintf!\n");fprintf(stderr,"stderr:hello fprintf!\n");return 0;
}
如果直接运行的话,肯定会全部打印。但是如果对该执行文件进行输出重定向的话,标准错误流的文件内容就不会重定向进新文件中。
这是因为输出重定向默认关闭的是1号文件描述符,并没有关闭2号文件描述符。利用这一特性,我们就可以以后将错误信息单独提前出来,打印到日志系统中。
当然如果想将标准输出与标准输出的内容输出到同一文件中,也可以使用类似的指令。
1.4 dup2函数
其中Linux
操作系统也为了我们提供了专门的重定向接口——dup2
函数
- 原型:
- 函数功能:
dup2
会将fd_array[oldfd]
的内容拷贝到fd_array[newfd]
当中,如果有必要的话我们需要先关闭文件描述符为newfd
的文件。- 函数返回值: 如果调用成功,返回
newfd
,否则返回-1。
使用dup2函数
时,需要注意以下两点:
- 如果
oldfd
不是有效的文件描述符,dup2
就会调用失败,此时文件描述符为newfd
的文件没有被关闭。- 如果
oldfd
是一个有效的文件描述符,但是newfd
和oldfd
具有相同的值,则dup2
不做任何操作,并返回newfd
。
#include<stdio.h>
#include<unistd.h>
#include<sys/stat.h>
#include<sys/types.h>
#include<fcntl.h>
int main()
{int fd=open("log.txt",O_WRONLY|O_CREAT,0666);if(fd<0){perror("open fail:");return 1;}close(1);dup2(fd,1);//进行重定向printf("hello printf!\n");fprintf(stdout,"hello fprintf!\n");close(fd);return 0;
}
2. 缓冲区
2.1 语言缓冲区
在计算机领域,缓冲区是一块存储区域。它用于暂存数据,以协调不同速度的设备或操作之间的数据传输。比如我们再来看看下面这段代码:
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
int main()
{close(1);//关闭标准输出流int fd=open("log.txt",O_WRONLY|O_CREAT,0666);if(fd<0){perror("open fail:");return 1;}//向屏幕打印信息printf("hello betty!\n");printf("hello betty!\n");printf("hello betty!\n");printf("hello betty!\n");printf("hello betty!\n");close(fd);return 0;
}
为什么没有打印信息呢?其实这就与我们C语言的缓冲区有关,因为缓冲区常见的刷新策略有三种:
- 无缓冲。
- 行缓冲。(常见的对显示器进行刷新数据)
- 全缓冲。(常见的对磁盘文件写入数据)
其中对于我们的printf
函数,如果没有加\n
就是全缓冲,否则就是行缓冲。
因为我们对文件进行了重定向,让本应该向屏幕打印的信息输入进一个磁盘文件,这时缓冲策略就从行缓冲变成了全缓冲,全缓冲需要程序结束之后才会向磁盘刷新文件内容,但是在此之前文件我们已经调用close
接口关闭了对于的文件描述符,此时程序结束后就无法找到对应的文件,自然也不会对文件进行任何写入。所以一般为了解决这个问题,我们可以使用fflush
函数提前刷新缓冲区。
由于我们使用的printf
是C语言提供的接口,所以这个缓冲区也是C语言提供的,其被包含在名为File
的结构体中,不光是缓冲区,文件描述符fd
也被包含在其中。这也是为什么C语言的文件接口需要返回File*
的原因。
//在/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
};
2.2 系统缓冲区
不仅是我们语言方面存在缓冲区,我们操作系统内部也会存在一个缓冲区,我们一般称为内核缓冲区。同样语言缓冲区刷新到系统缓冲区也遵循三种刷新策略:
- 无缓冲。
- 行缓冲。(常见的对显示器进行刷新数据)
- 全缓冲。(常见的对磁盘文件写入数据)
所以说我们使用语言所提供的接口如printf
对文件进行写入数据,首先会将数据存放在语言缓冲区,然后根据不同的刷新规则再刷新到系统缓冲区中,最后才会将系统缓冲区的数据刷新到磁盘或者对应的外设之中。
比如说我们看看下面这段代码:
#include <stdio.h>
#include <unistd.h>
int main()
{//cprintf("hello printf\n");fputs("hello fputs\n", stdout);//systemwrite(1, "hello write\n", 12);fork();return 0;
}
为什么重定向之后的内容会与之前截然不同呢?
这是因为我们执行可执行程序,打印到屏幕,默认是行缓冲,所以直接打印所以数据。但是如果我们对数据进行重定向的话,向磁盘写入数据,默认为全缓冲,此时数据都会存在语言缓冲区中。而此时我们创建子进程,父子进程之间代码数据共享,进程结束之后对语言缓冲区进行刷新,本质就是对数据进行修改,为了进程之间的独立性,就会发生写实拷贝,所以重定向之后C语言接口的数据打印会答应两份。而因为系统接口
write
写入的数据是直接写入系统缓冲区的,不需要发生写实拷贝,所以只打印一份。
3. 理解文件系统
前面我们谈论的文件都是加载进内存的内存文件,而接下来我们就来谈谈磁盘文件。
3.1 磁盘
磁盘是一种永久性存储介质,在计算机中,磁盘几乎是唯一的机械设备。与磁盘相对应的就是内存,但是内存是掉电易失存储介质,所以目前所有的普通文件都是在磁盘中存储的。
了解磁盘,我们首先需要了解一下几个常见的基本概念。
如果我们需要确定磁盘的哪个特定的区域,只需要找到对应的扇区,磁道,柱面即可。
3.2 磁盘分区
磁盘通常被称为块设备,一般以扇区为单位,一个扇区的大小通常为512字节。为了方便描述,我们可以将磁盘抽象为线性存储。
在计算机中,为实现高效磁盘管理,常进行分区操作。分区编辑器可在磁盘上划分出多个逻辑部分,如 Windows
下常见的C
盘和D
盘。分区越多,文件管理越精细,不同性质文件可存储于不同分区。这样能更好地组织和管理文件,提升系统运行效率,便于用户快速找到所需文件,优化计算机使用体验。
在Linux
操作系统中,我们也可以通过指令ll /dev/vda*
查看我们磁盘的分区信息。
3.3 磁盘格式化
磁盘格式化是在磁盘完成分区后进行的一项重要操作。从本质上来说,它是对磁盘中的分区进行初始化,旨在为数据存储和管理建立一个规范的基础结构。
其中,初始化会写入相应的管理信息,这些管理信息是由文件系统决定的,不同的文件系统格式化时写入的管理信息是不同的,常见的文件系统有EXT2
、EXT3
、XFS
、NTFS
等。
需要强调的是,磁盘格式化具有一定的风险性。在进行这一操作时,通常会导致现有的磁盘或分区中所有的文件被完全清除,且这种清除往往是不可逆的。因此,在决定进行磁盘格式化之前,必须谨慎考虑并确保已对重要文件进行了妥善的备份。
3.4 inode
在Linux
操作系统中,文件的元信息和内容是分离存储的,其中保存元信息的结构称之为inode
,因为系统当中可能存在大量的文件,所以我们需要给每个文件的属性集起一个唯一的编号,即inode
编号。
其中我们可以通过指令ls -i
,显示当前目录下各文件的inode
编号。
在Linux
下,文件是通过innode
标识的,所以在系统层面文件名,后缀都是没有意义的。
3.5 EXT2文件系统的存储方案
对于每一个分区来说,分区的头部会包括一个启动块(Boot Block
),对于该分区的其余区域,EXT2
文件系统会根据分区的大小将其划分为一个个的块组(Block Group
)。其中启动块的大小是确定的,而块组的大小是由格式化的时候确定的,并且不可以更改。
并且,每个组块都有着相同的组成结构,每个组块都由超级块(Super Block
)、块组描述符表(Group Descriptor Table
)、块位图(Block Bitmap
)、inode
位图(inode Bitmap
)、inode
表(inode Table
)以及数据表(Data Block
)组成。
Super Block
: 存放文件系统本身的结构信息。记录的信息主要有:Data Block
和inode
的总量、未使用的Data Block
和inode
的数量、一个Data Blocks
和inode
的大小、最近一次挂载的时间、等其他文件系统的相关信息。Super Block
的信息被破坏,可以说整个文件系统结构就被破坏了。Group Descriptor Table
: 块组描述符表,描述该分区当中块组的属性信息。Block Bitmap
: 块位图当中记录着Data Block
中哪个数据块已经被占用,哪个数据块没有被占用。inode Bitmap
:inode
位图当中记录着每个inode
是否可用。inode Table
: 存放文件属性,即每个文件的inode
。Data Blocks
: 存放文件内容。
值得注意的是:
- 其他块组当中可能会存在冗余的
Super Block
,当某一Super Block
被破坏后可以通过其他Super Block
进行恢复。- 磁盘分区并格式化后,每个分区的
inode
个数就确定了。
一个文件使用的数据块和inode
结构的对应关系,是通过一个数组进行维护的,该数组一般可以存储15个元素,其中前12个元素分别对应该文件使用的12个数据块,剩余的三个元素分别是一级索引、二级索引和三级索引,当该文件使用数据块的个数超过12个时,可以用这三个索引进行数据块扩充。
通过上面的学习,我们就可以回答一下几个问题。
- 如何理解创建一个空文件?
- 遍历
inode Bitmap
,找到比特位为0的位置,申请一个未被使用的inode
。- 将
inode
表中找到对应的inode
, 并将文件的属性信息填到inode
结构当中。- 将该文件的文件名和
inode
指针添加到目录文件的数据块当中。
- 如何理解向文件写入信息?
- 通过文件的
inode
编号找到对应的inode
结构。- 通过
inode
结构找到存储该文件内容的数据块,并将数据写入数据块。- 若不存在数据块或者申请的数据块已经写满了,就需要遍历
block Bitmap
找到一个空的块号,并在数据区当中找到对应的空闲块,再把数据写入到数据块当中,最后还需要建立数据块和inode
结构的对应关系。
- 删除文件做了些什么?
- 将该文件对应的
inode
在Inode map
当中设置为无效。- 将该文件申请过的
Data Block
在Block map
当中置为无效。
这也是我们为什么删除一个软件的速度比下载同一个软件的速度快的多的原因。当然因为文件内容并没有被删除,所以我们可以在对应内容被其他文件内容覆盖之前,通过一些技术手段复原已删除文件。
- 如何理解目录?
目录也是一种文件,是文件就有对应的文件属性与文件内容,其中对应的文件属性就是我们的
inode
存储的就是目录的大小,目录的拥有者等。而对应的文件内容存储的就是该目录下的文件名以及对应文件的inode
指针。
4. 软硬链接
4.1 软链接
软链接又叫做符号链接,软链接文件是一个独立的文件,该文件有自己的inode
号,但是该文件只包含了源文件的路径名,所以软链接文件一般就是对应路径文件的一种快捷访问方式。其中在Windows
系统中,我们桌面上软件图标就是访问对应程序的快捷方式,本质其实就是一个软连接文件。
在Linux
中,我们可以通过指令ln -s 文件名 软链接名
设置软连接:
并且我们也能通过指令unlink 软连接名
取消对应的软连接,并且如果一旦删除软连接所指向的文件,那么该软连接文件也将毫无意义。
4.2 硬链接
硬链接文件就是源文件的一个别名,它与源文件之间具有相同的inode
,大小。一旦为某个文件建立硬链接,那么对应的硬链接数就会加一。
硬链接没有独立的inode
,并不是一个独立的文件, 本质是在特定的目录下,添加一个文件名和inode
编号的映射关系。
在Linux
中,我们可以通过指令ln 文件名 硬链接名
建立对应的硬链接,同样我们也能通过unlink 硬链接名
取消对应的硬链接。
但是我们还可以提出一个疑惑就是,我们的普通文件的硬链接数为1,但是目录的硬链接数为什么不为1呢?
因为我们当前目录下还存在一个隐藏文件.
指向我们的当前目录,这个.
文件其实就是我们的目录的硬件链接文件。
5. 文件时间-ACM
在Linux
中,我们可以使用指令stat 文件名
来查看对应文件的信息。
以下是对应关于文件时间的信息。
Access
: 文件最后被访问的时间。Modify
: 文件内容最后的修改时间。Change
: 文件属性最后的修改时间。
当我们修改文件内容时,文件的大小一般也会随之改变,所以一般情况下Modify
的改变会影响Change
一起改变,但修改文件属性一般不会影响到文件内容,所以一般情况下Change
的改变不会影响Modify
的改变。
我们若是想将文件的这三个时间都更新到最新状态,可以使用指令touch 文件名
。
6. Linux下一切皆文件
最后我们学习完文件相关的知识后,再来谈一谈linux
下一切皆文件这一观点。
在Linux
系统中,“一切皆文件”是一个重要的设计理念。这一理念的实现涉及到多个层面的技术和机制。
首先,外设与内存进行交互,像键盘、显示器等外设都有诸如read
、write
等读写方法。但由于各种外设的硬件结构不同,这些方法在底层实现是不一样的,并且都是在硬件的驱动层完成。
那么,Linux
是如何做到“一切皆文件”的呢?首先Linux
引入了软件的虚拟层 VFS
(虚拟文件系统)。VFS
会统一维护每一个文件的结构体struct file
,这个结构体包含了一批函数指针。这些函数指针能够直接指向底层的方法。在上层,我们可以以统一的struct_file
的方式去看待文件。因此,“一切皆文件”指的是在 VFS
层面上的看待方式,而非在驱动层。
这种实现方式与C++中的多态类似。在 C++中,父类指针指向谁,调用的就是谁的方法。在 C 语言中,可以通过函数指针做到指向不同的对象时执行不同的方法,实现多态的性质。在Linux
中,每个struct file
中包含很多函数指针,这样在struct file
上层看来,所有的文件都是调用统一的接口,而在底层则通过函数指针指向不同硬件的方法,实现与具体硬件对应的逻辑。
相关文章:

[Linux]:文件(下)
✨✨ 欢迎大家来到贝蒂大讲堂✨✨ 🎈🎈养成好习惯,先赞后看哦~🎈🎈 所属专栏:Linux学习 贝蒂的主页:Betty’s blog 1. 重定向原理 在明确了文件描述符的概念及其分配规则后,我们就可…...

【学习笔记】手写Tomcat 一
目录 HTTP协议请求格式 HTTP协议响应格式 Socket 解读代码 服务端优化 解读代码 作业 1. 响应一个 HTML 页面给客户端,游览器把接收到的内容进行渲染 2. 文件的媒体类型是写死的,肯定不行,怎么变成动态? 昨天作业答案 …...
springboot基础-Druid数据库连接池使用
文章目录 引入Druid组件(maven)配置数据源Druid配置项1. 数据源配置2. 监控配置3. 安全配置4. SQL拦截配置 示例配置相关地址 Druid是阿里巴巴开源的一个高性能的Java数据库连接池组件,它提供了强大的监控统计功能和工具支持。Druid不仅可以作…...
C语言文件操作全攻略:从打开fopen到读写r,w,一网打尽
前言 在C语言中,文件操作是一项基础而强大的功能,它允许程序与存储在硬盘上的数据进行交互。无论是读取配置文件、处理日志文件,还是创建新的数据文件,C语言都提供了丰富的函数库来支持这些操作。本文将整合并详细介绍fopen(), 对…...
【0328】Postgres内核之 “User ID state”
1. User ID state 我们必须追踪与“用户ID(user ID)”概念相关的多个不同值。Postgres内核中有共有以下几个 User ID。 ✔ AuthenticatedUserId ✔ SessionUserId ✔ OuterUserId ✔ CurrentUserId 1.1 User ID 概念相关的不同值 AuthenticatedUserId AuthenticatedUserId…...

VisualStudio环境搭建C++
Visual Studio环境搭建 说明 C程序编写中,经常需要链接头文件(.h/.hpp)和源文件(.c/.cpp)。这样的好处是:控制主文件的篇幅,让代码架构更加清晰。一般来说头文件里放的是类的申明,函数的申明,全局变量的定义等等。源…...
linux 文件压缩并且切割压缩
Linux系统中,split命令是一个非常实用的工具,它可以将一个大文件分割成多个小文件 1、先将文件压缩 tar -cvf access.log.tar.gz access2、将文件压缩为每500mb一个文件,-b 500m 指定了每个分割文件的大小为500MB,-d 表示使用数字…...

支持iPhone 16新品预售,饿了么同步上线专人配送等特色服务
9月10日凌晨,2024年 Apple 秋季新品发布会上正式揭晓iPhone 16新机。9月10日一早,饿了么同步宣布:今年将携手近4000家Apple 授权专营店,支持iPhone 16新品预售及现货的同步开售。新机现货首发当日,饿了么消费者最快半小…...

低光增强效果展示
训练模型给图片加标题...
李诞-2021.8脱口秀工作手册-11-pitch your idea把一个想法扎进别人脑子里;专业,做足准备,给选择option!
17 每个人都该学会卖掉自己的想法 要把一件事办妥,就要有把一个想法扎进别人脑子里的决心。 很早之前,我跟编剧鬼顾达去见一个非常非常不好合作的嘉宾,我们本来带去了一份很好的稿子,他不愿意接受,反复抗议ÿ…...

vue3 自定义指令 directive
1、官方说明:https://cn.vuejs.org/guide/reusability/custom-directives 除了 Vue 内置的一系列指令 (比如 v-model 或 v-show) 之外,Vue 还允许你注册自定义的指令 (Custom Directives)。 我们已经介绍了两种在 Vue 中重用代码的方式:组件和…...

为什么腾讯难以再现《黑神话:悟空》这样的游戏大作?
自《黑神话:悟空》发布以来,它凭借令人惊艳的画面和深入人心的故事情节,迅速在全球范围内收获了大量粉丝。这款游戏的成功,不仅让全球玩家看到了国产游戏的新高度,也让许多人开始好奇:作为中国游戏行业的巨头,腾讯为什么没能推出类似《黑神话:悟空》这样震撼的作品?今…...

C# WPF燃气报警器记录读取串口工具
C# WPF燃气报警器记录读取串口工具 概要串口帧数据布局文件代码文件运行效果源码下载 概要 符合国标文件《GB15322.2-2019.pdf》串口通信协议定义;可读取燃气报警器家用版设备历史记录信息等信息; 串口帧数据 串口通信如何确定一帧数据接收完成是个…...

【IEEE独立出版 | 往届快至会后2个月检索,刊后1个月检索】2024年第四届电子信息工程与计算机科学国际会议(EIECS 2024)
在线投稿:学术会议-学术交流征稿-学术会议在线-艾思科蓝 电子信息的出现与计算机技术、通信技术和高密度存储技术的迅速发展并在各个领域里得到广泛应用有着密切关系。作为高技术领域中重要的前沿技术之一,电子信息工程具有前瞻性、先导性的特点&#x…...

FPGA实现串口升级及MultiBoot(三)FPGA启动加载方式
缩略词索引: K7:Kintex 7V7:Vertex 7A7:Artix 7 上一篇中介绍了FPGA的启动步骤,如图0 所示,今天这篇文章就要在上一篇文章基础上进行分支细化,首先我们先了解FPGA 启动加载的几种方式。同时对于我们设计中常见的几个问题将在文章最…...

Linux驱动(六):Linux2.6驱动编写之平台设备总线
目录 前言一、平台设备总线1.是个啥?2.API函数 二、设备端驱动端1. 匹配机制2. 实现代码 三、设备树驱动端1.匹配机制2.代码实现 前言 本文主要介绍了一下两种驱动编写方法: 1.比较原始的设备端驱动端编写方法。 2.效率较高的设备树驱动端编写方法。 最…...
回溯——11.重新安排行程
力扣题目链接 给定一个机票的字符串二维数组 [from, to],子数组中的两个成员分别表示飞机出发和降落的机场地点,对该行程进行重新规划排序。所有这些机票都属于一个从 JFK(肯尼迪国际机场)出发的先生,所以该行程必须从…...

python+pytest+request 接口自动化测试
一、环境配置 1.安装python3 brew update brew install pyenv 然后在 .bash_profile 文件中添加 eval “$(pyenv init -)” pyenv install 3.5.3 -v pyenv rehash 安装完成后,更新数据库 pyenv versions 查看目前系统已安装的 Python 版本 pyenv global 3.5…...

《JavaEE进阶》----10.<SpringMVC应用分层:【三层架构】>
本篇博客我们主要讲解 1.应用的分层:三层架构 2.Spring MVC和三层架构的区别和联系 3.软件设计原则:高内聚低耦合 4.应用分层的好处 5.通过应用分层后的代码示例 一、三层架构简介 阿里开发手册中,关于工程结构部分,定义了常见工程的应用分层结构: 上图…...

【网络】网络通信的传输方式
目录 1.网络通信中的两种基本通信模式 1.1.怎么理解连接 1.2.面向有连接类型 1.3.面向无连接类型 2.实现这两种通信模式的具体交换技术 2.1.电路交换 2.2.分组交换 3.根据接收端数量分类 单播(Unicast) 广播(Broadcast) …...
Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以?
Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以? 在 Golang 的面试中,map 类型的使用是一个常见的考点,其中对 key 类型的合法性 是一道常被提及的基础却很容易被忽视的问题。本文将带你深入理解 Golang 中…...

23-Oracle 23 ai 区块链表(Blockchain Table)
小伙伴有没有在金融强合规的领域中遇见,必须要保持数据不可变,管理员都无法修改和留痕的要求。比如医疗的电子病历中,影像检查检验结果不可篡改行的,药品追溯过程中数据只可插入无法删除的特性需求;登录日志、修改日志…...

Linux相关概念和易错知识点(42)(TCP的连接管理、可靠性、面临复杂网络的处理)
目录 1.TCP的连接管理机制(1)三次握手①握手过程②对握手过程的理解 (2)四次挥手(3)握手和挥手的触发(4)状态切换①挥手过程中状态的切换②握手过程中状态的切换 2.TCP的可靠性&…...

Vue2 第一节_Vue2上手_插值表达式{{}}_访问数据和修改数据_Vue开发者工具
文章目录 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染2. 插值表达式{{}}3. 访问数据和修改数据4. vue响应式5. Vue开发者工具--方便调试 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染 准备容器引包创建Vue实例 new Vue()指定配置项 ->渲染数据 准备一个容器,例如: …...

有限自动机到正规文法转换器v1.0
1 项目简介 这是一个功能强大的有限自动机(Finite Automaton, FA)到正规文法(Regular Grammar)转换器,它配备了一个直观且完整的图形用户界面,使用户能够轻松地进行操作和观察。该程序基于编译原理中的经典…...

均衡后的SNRSINR
本文主要摘自参考文献中的前两篇,相关文献中经常会出现MIMO检测后的SINR不过一直没有找到相关数学推到过程,其中文献[1]中给出了相关原理在此仅做记录。 1. 系统模型 复信道模型 n t n_t nt 根发送天线, n r n_r nr 根接收天线的 MIMO 系…...

Windows安装Miniconda
一、下载 https://www.anaconda.com/download/success 二、安装 三、配置镜像源 Anaconda/Miniconda pip 配置清华镜像源_anaconda配置清华源-CSDN博客 四、常用操作命令 Anaconda/Miniconda 基本操作命令_miniconda创建环境命令-CSDN博客...

GO协程(Goroutine)问题总结
在使用Go语言来编写代码时,遇到的一些问题总结一下 [参考文档]:https://www.topgoer.com/%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B/goroutine.html 1. main()函数默认的Goroutine 场景再现: 今天在看到这个教程的时候,在自己的电…...
在 Spring Boot 项目里,MYSQL中json类型字段使用
前言: 因为程序特殊需求导致,需要mysql数据库存储json类型数据,因此记录一下使用流程 1.java实体中新增字段 private List<User> users 2.增加mybatis-plus注解 TableField(typeHandler FastjsonTypeHandler.class) private Lis…...
6个月Python学习计划 Day 16 - 面向对象编程(OOP)基础
第三周 Day 3 🎯 今日目标 理解类(class)和对象(object)的关系学会定义类的属性、方法和构造函数(init)掌握对象的创建与使用初识封装、继承和多态的基本概念(预告) &a…...