一 磁盘基础知识(非常通俗易懂)
- 扇区: 硬盘的最小读写单元
- 磁盘块/簇: 是操作系统针对硬盘读写的最小单元
- page: 是内存与操作系统之间操作的最小单元。
- 不同长度的磁道,扇区容量与个数是否相同?(磁道由外向内编号,最外圈是0磁道)
- 如果有一块空硬盘,写入一个文件,是不是先写满同一个磁道的所有扇区,然后再换一个磁道写入?
--------是的,而且写入的方式是从外到内,先写满最外的磁道,接着再写里面的磁道
为什么硬盘用久了读写速度会变慢?因为外面的磁道使用完了,开始用里面的磁道,越是里面的磁道读写速度越慢,同样的时间,读写头在外面磁道可以扫过10个扇区的面积,读写10个扇区的数据,但在里面的磁道只能扫过1个扇区的面积,读写1个扇区的数据,所以这时可以做磁盘整理或者格式化,这会使外面的磁道得到使用
二 文件系统的内部结构
0-术语概念
- 入口:目录中的列表的每一行就是一个入口(引用,硬链接)
- 符号链接(symlink):符号链接是通过文件名引用文件,而不是i-节点号
1-文件系统理解
磁盘分为最小单位扇区—>若干扇区又组成一个磁盘块—>磁盘块的序列又划分为三大部分:
- 超级块:文件系统的第一个磁盘块(什么是文件系统?文件系统的分类有哪些?)
- i-节点表:存放文件的属性信息(通常由系统调用stat得到),一个文件由一个i-结点唯一标识,一个i结点中有个数据块列表
,该数据块列表存储了数据块(都在数据区中)的位置序号(该文件的内容就存储在这些数据块中)
- 数据区:存放文件中的内容数据—>存放在若干磁盘块中(可以不连续)
2-目录是一种特殊文件
形象化理解:目录中存储着一个列表,列表的每一行代表着该目录下的一个文件或者目录,每一行有两个数据(一个是i-结点号,一个是文件名)
3-大文件的存储
- 一个 i-节点的数据块列表的长度是有限的
- 需要间接块,二级间接块,三级间接块
例:一个文件,它的i-节点的数据块列表长度为10,现在已经占据了7个位置。为防止表空间不够用,就在数据区开辟一个数据块,作为一个新数据块列表来存储数据块的位置序号,在i结点的数据块列表中,存放该新数据块的位置序号,此时该数据块被称为间接块。 - 间接块满时,在i结点中中存放二级间接块的的位置序号,二级间接块中存放(第2,3,4…块)间接块的位置序号。
- 二级间接块满时,开辟三级间接块,依次类推
- 最多只有三级间接块,再满了…买新硬盘吧
三 编写pwd命令
- stdout与stderr
* stdout与stderr都是把内容打印到终端界面
* stdout(标准输出),输出方式是行缓冲。输出的字符会先存放在缓冲区,等按下回车键时才进行实际的I/O操作。
* stderr(标准错误),是不带缓冲的,这使得出错信息可以直接尽快地显示出来。
* 因此,通常来说,输出到stderr的内容会比stdout更快打印出来(除非遇到换行符’\n’) - 编写思路
- 首先得到当前目录的inode
- 然后系统调用chdir("…")回到上级目录,在上级目录中根据inode找到本级目录的名字,存储下来。递归函数完成后,打印输出。
- 继续得到当前目录的inode,并回到上级目录
- 显然的递归思路方法—重要的一点便是路径的打印:先递归,递归到底后就倒着打印文件名,进行输出,便解决了字符串的连接问题,直接输出路径
代码如下:
#include<dirent.h>
#include<sys/stat.h>
#include<sys/types.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
char buffer[256];
int printPath(ino_t);
void ino_to_name(ino_t,char*);
ino_t get_inode(char*);
int main(){
printPath(get_inode("."));
printf("\n");
return 0;
}
int printPath(ino_t inode){
ino_t pre_inode=get_inode("..");
if(pre_inode!=inode){
char name[255];
memset(name,0,sizeof(name));
chdir("..");
ino_to_name(inode,name);
printPath(get_inode("."));
printf("%s/",name);
return 1;
}
return 0;
}
void ino_to_name(ino_t inode,char*buf){
DIR* dir;
dir=opendir(".");
struct dirent *tmp=(struct dirent*)malloc(sizeof(struct dirent));
if(dir==NULL){
perror("目录打开失败");
return;
}
memset(buf,0,sizeof(buf));
while( ( tmp=readdir(dir) ) != NULL){
if(tmp->d_ino==inode){
strcpy(buf,tmp->d_name);
closedir(dir);
return;
}
}
}
ino_t get_inode(char*filename){
char buf[256];
struct stat tmp;
if(stat(filename,&tmp)){
perror("无法获取文件信息");
return -1;
}
return tmp.st_ino;
}