政务移动门户网站建设方案,定制小程序开发公司收费,腾讯企点怎么注册,门户网站简介上次介绍了#xff1a;Linux#xff1a;基础IO#xff08;一.C语言文件接口与系统调用、默认打开的文件流、详解文件描述符与dup2系统调用#xff09; 文章目录 1.缓冲区1.1概念1.2作用与意义 2.语言级别的缓冲区2.1刷新策略2.2具体在哪里2.3支持格式化 3.自己来模拟一下缓…上次介绍了Linux基础IO一.C语言文件接口与系统调用、默认打开的文件流、详解文件描述符与dup2系统调用 文章目录 1.缓冲区1.1概念1.2作用与意义 2.语言级别的缓冲区2.1刷新策略2.2具体在哪里2.3支持格式化 3.自己来模拟一下缓冲区3.1项目文件规划3.2mystdio.h3.3mystdio.c3.4test.c 4.文件系统4.1磁盘机械结构4.2磁盘的物理存储4.3磁盘的逻辑存储4.4文件系统 5.文件名5.1再看文件的增删改查 1.缓冲区
1.1概念
在计算机中内存被划分为不同的区域其中一部分被用作缓冲区用于临时存储数据 内存区域 物理结构计算机的内存是由许多存储单元组成的每个存储单元都有一个唯一的地址。这些存储单元按照地址顺序排列形成了一块连续的内存区域。访问方式程序可以通过地址访问内存中的数据读取或写入存储单元的内容。不同的内存区域有不同的用途例如代码区、数据区、堆区和栈区等。 缓冲区 定义缓冲区是内存中的一块区域用于临时存储数据。通常用于临时存储输入数据、输出数据或中间数据以便程序能够有效地处理这些数据。特点缓冲区是一种有限大小的内存区域数据在缓冲区中暂时存储等待被处理或传输到目标设备。用途缓冲区在计算机程序设计中被广泛应用例如用于输入输出操作、网络通信、文件读写等场景。 缓冲区的工作原理 输入缓冲区当数据被输入到程序中时数据首先被存储在输入缓冲区中。程序可以逐个字符或一定量的数据从输入缓冲区中读取进行处理。输出缓冲区当程序输出数据时数据首先被存储在输出缓冲区中。系统会根据缓冲区的策略或限制将数据逐个字符或一定量的数据发送到目标设备。
缓冲区作为一块内存区域提供了一个临时存储数据的空间帮助程序高效地处理输入和输出 打开一个文件进行读取或写入时文件内容并不是直接加载到整个内存中而是加载到内存中的一个特定区域即缓冲区Buffer。缓冲区是内存中的一个临时存储区域用于存储从文件读取的数据或待写入文件的数据。 在读取文件时操作系统会一次性从磁盘读取一定数量的数据块到缓冲区中然后程序可以从这个缓冲区中读取数据而不是每次都直接从磁盘读取。这样可以减少磁盘I/O操作的次数提高读取效率。 在写入文件时程序会将数据写入到缓冲区中而不是直接写入到磁盘。当缓冲区满或者程序显式调用flush方法或关闭文件时缓冲区中的数据才会被一次性写入到磁盘中。这种延迟写入的方式也可以提高写入效率并减少磁盘操作的次数。 需要注意的是缓冲区的大小是有限的它不能无限地存储数据。因此在处理大文件时数据会分批次地加载到缓冲区中并进行处理。同时缓冲区的管理是由操作系统和文件系统来负责的程序员通常不需要直接操作缓冲区而是通过文件I/O函数或方法来间接地使用缓冲区。 1.2作用与意义
缓冲区在计算机系统中具有的意义和作用主要体现在以下几个方面 数据传输的效率缓冲区可以暂时存储数据使得数据传输过程中的速度更加稳定和高效。当数据产生和消费的速度不匹配时缓冲区可以平衡数据的传输避免数据丢失或传输阻塞。 数据处理的灵活性缓冲区可以暂时存储数据使得程序能够按照自己的速度处理数据而不受外部数据产生或消费速度的限制。这种灵活性有助于提高程序的性能和稳定性。 数据交互的安全性缓冲区可以对输入数据进行有效的验证和处理防止恶意输入或缓冲区溢出等安全问题。通过合理设置缓冲区大小和数据校验机制可以保护系统免受攻击。 系统资源的管理缓冲区可以帮助管理系统资源的分配和使用避免资源的浪费和不必要的阻塞。通过合理设计缓冲区的大小和处理策略可以优化系统的性能和资源利用率。 最主要的是提高效率聚集数据一次拷贝 2.语言级别的缓冲区 在文件I/O操作中提到的缓冲区既可以是操作系统级别的也可以是C语言标准库或特定编程语言库提供的。这两者在某些情况下是协同工作的但它们的实现和用途有所不同。
操作系统级别的缓冲区
当操作系统读取或写入文件时它通常会使用内部缓冲区来优化磁盘操作。操作系统会根据需要将一部分数据从磁盘读取到内存中的缓冲区或者将缓冲区中的数据写入磁盘。这种缓冲区的管理对应用程序来说是透明的应用程序不需要直接与之交互。
C语言标准库提供的缓冲区 在C语言中标准库函数如fread、fwrite、fgetc、fputc等也使用了缓冲区。这些函数在内部维护了一个缓冲区用于存储从文件读取的数据或待写入文件的数据(通常被称为“用户空间缓冲区”或“标准I/O缓冲区”。)。当使用这些函数进行文件操作时数据首先被读取或写入到这个内部缓冲区然后再由库函数决定何时将数据从缓冲区传输到磁盘或从磁盘加载到缓冲区。 当你调用例如fwrite函数写入数据时这些数据首先被写入到这个用户空间缓冲区中而不是直接写入到操作系统或硬件的缓冲区。当缓冲区满或者显式调用fflush函数时C语言标准库才会将缓冲区中的数据传递给操作系统由操作系统进一步处理。 操作系统也有自己的缓冲区用于与硬件进行交互例如磁盘I/O。操作系统的缓冲区通常被称为“内核缓冲区”或“系统缓冲区”。这些缓冲区用于在内核空间与用户空间之间传输数据以及将数据从内存传输到磁盘或从磁盘加载到内存。 因此可以说C语言的缓冲区用户空间缓冲区在将数据写入文件时会先将数据存储在用户空间的缓冲区中然后在适当的时候如缓冲区满或显式调用fflush将数据传递给操作系统的缓冲区系统缓冲区最后由操作系统负责将数据写入磁盘。 这里c语言级别的缓冲区能大大减少我们调用系统调用的次数。 也是提高效率 没有缓冲区时我们每有一个字符就要调用一次系统接口write()函数 此时有了缓冲区我们可以每次放进缓冲区里最后再进行调用系统接口。只要调用一次 系统调用也是有成本的 有了缓冲区能大大提高c语言中io函数的返回效率减少使用时间。 如printf函数只要写到缓冲区后就能返回了 仔细一想我们用户也只能通过调用OS提供的接口来让OS进行文件操作那么c语言的缓冲区就是在调用系统接口上进行的优化 2.1刷新策略
缓冲区的刷新策略指的是何时将缓冲区中的数据写入到输出设备或从输入设备读取新数据的策略。在 C 语言中通常有以下几种缓冲区刷新策略
全缓冲当缓冲区填满或者遇到换行符 \n 时缓冲区会被刷新数据被写入到输出设备或者从输入设备读取新数据。这种策略通常用于文件 I/O 操作例如 stdio 中的 FILE 结构。行缓冲当遇到换行符 \n 时缓冲区会被刷新数据被写入到输出设备或者从输入设备读取新数据。这种策略通常用于标准输入/输出流例如 stdout 和 stdin。无缓冲数据不会被缓存而是立即写入到输出设备或者从输入设备读取。这种策略通常用于特定的设备或者特殊的 I/O 操作。 当我们强制刷新时或者进程结束。缓冲区也会刷新 在 C 语言中可以使用 setbuf()、setvbuf() 和 fflush() 等函数来控制缓冲区的刷新策略。例如fflush() 函数可以强制将缓冲区中的数据立即写入到输出设备而不必等到缓冲区被填满或遇到换行符。
2.2具体在哪里 #include stdio.h
#include fcntl.h
#include unistd.h
#includestring.h
int main()
{const char* s1 write\n;write(1, s1, strlen(s1));const char* s2 fprintf\n;fprintf(stdout, %s, s2);const char* s3 fwrite\n;fwrite(s3, strlen(s3), 1, stdout);return 0;
}这里我们把结果重定向到test.txt。现在是正常的但是下面我们做出一些改动。 int main()
{const char* s1 write\n;write(1, s1, strlen(s1));const char* s2 fprintf\n;fprintf(stdout, %s, s2);const char* s3 fwrite\n;fwrite(s3, strlen(s3), 1, stdout);fork();return 0;
}一开始我们都是向标准输出打印采用行缓冲的刷新策略但是我们使用重定向到test.txt 文件了刷新策略变为全缓冲 fprintf与fwrite都是写入进stdout的缓冲区。缓冲区本身也是数据。 进程结束时会刷新缓冲区刷新到操作系统。刷新的本质就是清空也是修改数据那就会发生写时拷贝 父进程与子进程都刷新一次一共两次 write接口是直接放到操作系统的缓冲区的与进程没有关系 当调用 write 系统调用时数据会被写入到操作系统的内核缓冲区中。内核缓冲区是操作系统用来暂存数据的内存区域数据在这里等待被写入到文件中 2.3支持格式化
缓冲区在 C 语言中支持输入输出的格式化操作使得程序员可以方便地对输入和输出的数据进行格式化处理。键盘和显示器都是字符设备通过缓冲区的格式化操作可以实现对键盘输入和显示器输出的数据进行格式化控制。 输入格式化操作当用户从键盘输入数据时这些数据首先会被存储在输入缓冲区中。程序员可以使用输入格式化函数如 scanf() 来从输入缓冲区中读取数据并根据指定的格式进行解析和处理 输出格式化操作当程序需要将数据输出到显示器时这些数据会先被存储在输出缓冲区中。程序员可以使用输出格式化函数如 printf() 来将数据按照指定的格式输出到显示器上。通过格式化字符串中的格式控制符可以指定输出的数据类型、宽度、精度等信息。 3.自己来模拟一下缓冲区
3.1项目文件规划 mystdio.h用来编写FILE结构体和各种接口的声明mystdio.c用来具体实现各种接口test.c用来进行功能的测试 makefile内容一览
filetest:mystdio.c test.cgcc -o $ $^
.PHONY:clean
clean:rm filetest -f3.2mystdio.h
#pragma once#define SIZE 4096//缓冲区大小
#define NONE_FLUSH (11)
#define LINE_FLUSH (12)
#define FULL_FLUSH (13) //三种刷新模式typedef struct _myFILE
{//...char outbuffer[SIZE];//这是缓冲区int pos;//这是缓冲区下标int cap;//缓冲区容量int fileno;//文件的no编号int flush_mode;//缓冲区刷新模式
}myFILE;myFILE* my_fopen(const char* pathname, const char* mode);int my_fwrite(myFILE* fp, const char* s, int size);void my_fflush(myFILE* fp);void my_fclose(myFILE* fp);
3.3mystdio.c
#includestdio.h
#include string.h
#include sys/stat.h
#include sys/types.h
#include fcntl.h
#include stdlib.h
#include unistd.h
#include4.22.hmyFILE* my_fopen(const char* pathname, const char* mode)
{int flag 0;if (strcmp(mode, r) 0){flag | O_RDONLY;}else if (strcmp(mode, w) 0){flag | (O_CREAT | O_WRONLY | O_TRUNC);}else if (strcmp(mode, a) 0){flag | (O_CREAT | O_WRONLY | O_APPEND);}else{return NULL;}int fd 0;if (flag O_WRONLY){fd open(pathname, flag, 0666);}else{fd open(pathname, flag);}if (fd 0){return NULL;}myFILE* myf (myFILE*)malloc(sizeof(myFILE));myf-pos 0;myf-cap SIZE;myf-fileno fd;myf-flush_mode LINE_FLUSH;return myf;
}void my_fflush(myFILE* fp)
{write(fp-fileno, fp-outbuffer, fp-pos);fp-pos 0;
}int my_fwrite(myFILE* fp, const char* s, int size)
{memcpy(fp-outbufferfp-pos, s, size);fp-pos size;if (fp-flush_mode LINE_FLUSH fp-outbuffer[fp-pos - 1] \n){my_fflush(fp);}else if (fp-flush_mode LINE_FLUSH fp-capfp-pos){my_fflush(fp);}
}void my_fclose(myFILE* fp)
{my_fflush(fp);close(fp-fileno);free(fp);fp NULL;
}3.4test.c
#includemystdio.h
#includestdio.h
#includestring.hconst char* filename./log.txt;int main()
{myFILE* fpmy_fopen(filename,w);if(fpNULL) return 1;const char* bufferhellow,there are myfile;my_fwrite(fp, buffer, strlen(buffer));my_fclose(fp);return 0;
} 4.文件系统
4.1磁盘机械结构 硬盘驱动器是计算机中常见的数据存储设备它由多个组件组成其中包括盘片、磁头、主轴、马达等 盘片Platter硬盘驱动器通常包含多个盘片每个盘片都是一个圆形的磁性介质通常由金属或玻璃制成表面被覆盖上磁性材料。数据存储在盘片的表面上每个盘片都有内侧和外侧两面数据存储在不同的磁道上。 磁头Head硬盘驱动器中的磁头负责读取和写入数据。磁头通过在盘片表面上移动来访问不同位置上的数据它可以在盘片上创建磁场来表示数据的0和1。通常硬盘驱动器会有多个磁头每个磁头对应一个盘面可以同时读写多个盘片上的数据。 磁头的来回是为了定位磁道的盘片的旋转是为了定位寻址制定磁道上的扇区的 主轴Spindle主轴是硬盘驱动器中的一个旋转部件它负责旋转盘片。盘片被安装在主轴上主轴通过马达驱动盘片旋转通常转速在几千转每分钟到一万转每分钟之间不同硬盘驱动器的转速可能有所不同。 马达Motor硬盘驱动器中的马达负责驱动主轴旋转、移动磁头和控制盘片的位置。马达通常包括主轴电机、磁头马达和定位马达等部件它们协同工作以确保盘片的旋转、磁头的移动和数据的读写。 控制器Controller硬盘驱动器中的控制器负责管理数据的读写、磁头的移动、盘片的旋转等操作。控制器通常包括逻辑控制器和驱动器电路板它们与计算机系统进行通信控制硬盘驱动器的各项功能。 我们之前说的0与1实际上只是一种抽象的概念。在不同的设备和存储介质中0和1的表示方式可能会有所不同这取决于具体的存储技术和物理原理 盘片上的数据存储是通过磁性材料来实现的磁性材料可以在不同的磁场方向上表示0和1 磁性材料盘片表面被覆盖上一层磁性材料通常是氧化铁或类似的磁性材料。这种磁性材料可以在外加磁场的作用下保持磁性并且可以在不同方向上表示不同的磁极性从而实现数据的存储。磁场的方向硬盘驱动器中的磁头可以在盘片表面上创建磁场通过改变磁场的方向来表示数据的0和1。当磁场方向朝向盘片表面时表示为1当磁场方向远离盘片表面时表示为0。通过这种方式磁头可以在盘片上创建一系列的磁场来表示数据的二进制形式。 4.2磁盘的物理存储 硬盘的物理储存结构主要包括磁道、扇区和柱面这些是硬盘上数据存储的基本单位。下面我将简要解释它们的含义和作用
磁道硬盘的盘片表面被划分成多个同心圆环每个环称为一个磁道每一个都有自己的编号。磁道是硬盘上的存储单位之一数据在磁道上被存储和组织。硬盘的磁头可以沿着磁道移动读取或写入数据。扇区每个磁道被划分成若干个扇区扇区是硬盘上存储数据的最小单位基本单位。通常一个扇区的大小是512字节或4KB。当数据被写入硬盘时它会被分割成适当大小的扇区并存储在硬盘的不同扇区中。柱面硬盘上的每个盘片都有多个磁道而所有盘片上相同位置的磁道组成一个柱面。磁头可以同时读取或写入同一柱面上的多个磁道这有助于提高数据的读写效率。盘面硬盘的盘片表面被划分成多个盘面每个盘面都可以存储数据。通常硬盘有多个盘片叠在一起每个盘片都有两个盘面正面和背面每一个也有自己的编号 如果我们想要定位一个扇区 定位到柱面确定是柱面里的哪一个磁头找到目标扇区 上述方法称之为CHS柱面、磁头、扇区定位法。系统会通过柱面号、磁头号和扇区号来唯一地确定硬盘上的一个位置。通过这种方式系统可以精确地定位到目标扇区以读取或写入文件的数据。 任何文件就是由多个扇区的数据构成的系统在读取或写入文件时会逐个扇区地进行操作
4.3磁盘的逻辑存储 那么如何通过下标来确定实际位置呢下标如何转变CHS 确定盘片首先将数组下标除以单盘的大小(一个盘的扇区数量)得到该数组元素所在的盘片号。 计算在盘片内的偏移量将数组下标取模单盘大小得到在盘片内的偏移量。 确定磁道将在盘片内的偏移量除以一个磁道的扇区个数得到该数组元素所在的磁道号。 确定扇区将在盘片内的偏移量取模一个磁道的扇区个数得到该数组元素所在的扇区号。 最终的物理地址即为盘片号、磁道号和扇区号的组合。 最后我们把一个800G的磁盘管理经过分区分组。转变为对10G的区域进行管理那具体怎么管理呢 我们先来看看Linux下的文件特性 文件内容属性 内容的大小不确定可能很大可能很小 属性的大小是固定的属性的类别是一样的但是每个类别里的内容不一样。文件名不属于属性 struct inode//文件的属性集
{//类型//大小//权限//时间//...int inode_num;//inode的编号
};大小是固定的128字节4kb/128b32(一个数据块block能存32个文件的属性)。 系统中标识一个文件使用的是inode inode编号在一个分区里是唯一的 i节点表inode Table:存放文件属性如文件大小所有者最近修改时间等。里面存的是一个个inode 表里面那么多inode我们如何知道哪个被使用哪个没有使用 inode位图inode Bitmap每个bit表示一个inode是否空闲可用 比特位的位置代表第几个inode 比特位的位置内容代表这个inode是否被使用 数据区Data blocks存放文件内容这是一个非常非常大的区里面有很多4kb的小数据块 下面我们可以看到最多对应15个block那文件内容太大不够用怎么办 下标[011]就正常存使用的block保存文件的内容下标[1213]指向的block里存的其他被使用的block的编号下标[14]指向的block里存的也是其他block的编号这些block里存的又是被使用的block的编号 块位图Block BitmapBlock Bitmap中记录着Data Block中哪个数据块已经被占用哪个数据块没有被占用 比特位的位置代表第几个4kb的数据块 比特位的位置内容代表这个数据块是否被使用 struct inode
{//...int block[15];//里面对应一个个使用的数据块的编号//...
};那么现在我们有了文件的inode编号后就能在inode Table里找到inode然后能进一步找到block该文件对应的数据块和其他属性 GDTGroup Descriptor Table块组描述符描述块组属性信息一个块的宏观使用情况 超级块Super Block存放文件系统本身的结构信息。记录的信息主要有bolck 和 inode的总量未使用的block和inode的数量一个block和inode的大小最近一次挂载的时间最近一次写入数据的时间最近一次检验磁盘的时间等其他文件系统的相关信息。Super Block的信息被破坏可以说整个文件系统结构就被破坏了不是所有的block group里都有super block个别才有 多个super block是为了进行数据备份 不是全都有是因为每次一变动每个都要更新。降低了效率 Super Block 的备份通常是为了提高文件系统的容错性和可靠性。每个 Block Group 并不一定都有 Super Block而是选择性地放置。这样做可以减少每次写操作时需要更新的 Super Block 数量从而提高文件系统的性能 新建一个文件都干了什么呢 在inode位图中找到一个未被使用的inode编号 填写inode结构体根据新的inode编号在inode表里找到填写inode结构体包括文件的属性信息如文件类型、权限、大小、创建时间等和指向数据块的指针 更新inode表将填写好的inode结构体写入inode表中以便后续查找和访问。同时更新inode位图中对应inode的状态为已占用。 分配数据块根据文件大小和文件系统的块大小确定需要分配的数据块数量并在块位图中找到未被使用的数据块。将这些数据块分配给新文件并更新块位图中对应数据块的状态为已占用。 将文件内容写入数据块将文件的内容写入分配的数据块中以完成文件的创建。文件的内容可以是文本、图像、音频等任意类型的数据。 删除一个文件呢 找到文件的inode首先通过文件名在目录结构中查找到文件对应的inode号码。释放数据块根据文件的inode结构体中记录的数据块指针找到文件所占用的数据块并将这些数据块标记为未使用状态以便后续被其他文件使用。更新inode位图和块位图将文件的inode和数据块对应的位图中的相应位标记为未使用状态以释放这些资源。 这里我们看到不对数据块里的内容进行清理只是标志为未使用这样效率更快。数据块内容会在后续被其他文件写入时覆盖或者由文件系统的垃圾回收机制在需要时清理 找一个文件就是通过inode编号找前提:我们怎么知道文件在哪一个分组里面 4.4文件系统
我们上面讲的那个区域里的文件系统称为Ext* 。是一系列的 Linux 文件系统最常见的是 Ext2、Ext3 和 Ext4
每一个分区有自己的文件系统。我们对分区初始化本质是向指定分区写入全新的文件系统
Ext2Second Extended File System
特点 Ext2 是 Linux 中最早的可用文件系统之一它是 Ext 文件系统的改进版本引入了许多新的特性如索引节点 (inode) 和快速文件系统 (Fast File System)。优点 Ext2 文件系统简单、可靠并且在 Linux 社区得到了广泛的支持和应用。它的设计目标是提供一个高性能的文件系统同时保持数据的稳定性和一致性。缺点 Ext2 文件系统不支持日志功能因此在系统崩溃或意外断电时可能会导致数据丢失或损坏。同时Ext2 文件系统没有提供数据的回收和压缩功能会导致存储空间的浪费。
5.文件名
前面我们的起点都是inode编号那我们一开始怎么得到inode呢
目录也是文件。目录inode目录的内容目录的内容都是——目录里的文件名与inode编号的映射关系内容实际上就是一个映射表将文件名映射到对应的inode编号。当你查看一个目录的内容时你实际上是在查看这个映射表。这就是为什么目录本身也是一个文件并且也有它自己的inode 我们之前讲过对于目录没有w权限就不能添加、删除文件。因为这些涉及对目录文件内容的修改 对于目录没有r权限那么你将无法查看目录中的文件列表。因为我们无法读文件内容不能查看文件名与inode编号的映射关系 5.1再看文件的增删改查 对一个文件进行的增删查改操作都与该文件所处的目录有密切关系。这是因为文件系统中的文件和目录是以树形结构组织的每个文件都通过其所在的目录进行定位和管理 那么我们想要知道目录的inode那就要知道目录所处目录的内容才能知道目录对应的inode。以此类推 想要找到一个文件我们要有路径首先进行路径解析从根目录往下进行。系统能够最终定位到指定路径的文件或目录并获取其inode编号 增创建文件 在一个目录中创建一个新的文件需要为该文件分配一个新的inode号。在文件系统的inode表中查找一个未被使用的inode分配给新文件。在分组中分配数据块给新文件存储数据并将数据写入这些数据块中。在当前目录中将新文件的名称与分配的inode号建立映射关系这样就完成了新增文件的操作。 删删除文件 根据文件名称查找到对应的inode编号进而确定文件所在的分组。修改inode bitmap内容将该inode对应的位标记为未使用表示该inode已经被释放。文件内容使用的数据块并将这些数据块标记为未使用状态在当前目录文件中删除该文件的名称与inode编号的映射关系完成文件的删除操作。 查查找文件 根据文件名称查找到对应的inode编号确定文件所在的分组。根据inode编号找到文件的数据块信息获取文件的内容。 改修改文件 根据文件名称查找到对应的inode编号确定文件所在的分组。根据inode编号找到文件的数据块对数据块中的内容进行修改。 inode编号只在一个分区里是唯一的那我们怎么知道是在哪个分区 在Linux系统中被写入文件系统的分区在被使用之前需要进行“挂载”操作。挂载的主要目的是将文件系统的分区与目录树中的某个目录关联起来从而使得用户可以通过该目录访问和操作分区中的文件 在Linux系统中每个分区都会挂载到文件系统的某个挂载点mount point下。通过查看文件或目录的路径我们可以确定它所属的挂载点进而确定它所在的分区(能直接根据路径看在哪个分区里进行路径前缀匹配) 当在执行一些命令时如果没有指定完整的文件路径系统会根据当前进程的执行路径来查找文件。这是因为在Linux系统中有一个环境变量叫做PATH它包含了一系列目录路径系统会根据这些路径来搜索可执行文件。 类似的对于一些命令如find等如果您没有指定完整的路径系统会从当前目录开始搜索文件。这是因为这些命令会使用当前进程的工作目录作为搜索起点。 因此当您在执行命令时只提供文件名而没有路径时系统会首先在当前目录下搜索这个文件名然后再根据PATH环境变量或当前目录来查找文件。 系统会按照以下步骤来查找可执行文件 首先系统会检查当前进程的工作目录也就是执行命令时所处的目录下是否存在与提供的文件名相匹配的文件。如果找到了系统会执行该文件。 如果在当前工作目录下没有找到匹配的文件系统会继续在PATH环境变量指定的目录列表中逐个查找。PATH环境变量包含了一系列目录路径系统会按照这些路径的顺序来搜索可执行文件。 如果在PATH指定的所有目录中都没有找到匹配的文件系统会提示找不到文件的错误。 好啦这次内容到这里了。感谢大家支持