
文件在块设备上存储时,磁盘大致被分为三部分:
超级区
负责"块设备"空间的分配和回收,记录块设备空间哪里用了哪里没用。
inode节点区
数据区
数据区专门用于存放文件的数据。
存储数据时,实际上并不是数据有多少个字节,就分配对应多少的字节空间给你,为了便于助理空间高效管理,往往都是按块分配空间的,一块往往为4k字节(4*1024) 。
文件中的数据小于一块时,还是给你分配一块,当数据超过一块时,会给你再分配一块,当这一块又满了时,再给你分配一块。
不同的数据块之间不一定是连续的,块之间使用地址进行相互链接,也即是说每一块都有存放前后块的地址,通过地址就可以找到前后块空间。
每创建一个硬链接,文件就多一个文件名,硬件链接数+1
创建硬链接后所得到的多个文件名,指向的同一个inode节点,只有inode节点代表了文件的真实存在,inode节点只有一个,因此多个文件名指向的是同一个文件,不管使用的是哪一个文件名,都能操作这个文件。
记录了有多少个文件名指向这个inode节点,通过创建硬链接,每增加一个文件名,就多一个硬链接数。
同理,每删除一个一个硬链接,也就是删除一个文件名,就少一个硬链接数,当然硬链接数被减为0时,也就代表着文件名被删除完了,这个文件也就被删除了。
不过这里需要主要一点,当硬链接数被减为了0时,如果还有进程在操作这个文件的话,这个文件还会一直存在,直到进程结束后,这个文件才被删除。
删除文件后,文件数据还在,因为删除文件时,只是将文件的inode节点空间释放了,如果这个文件的数据没有被覆盖的话,只要将文件的inode节点空间恢复,即可还原该文件。
为什么新建的目录一开始的文件链接数就是2?
因为新创建的目录,一开始就有两个名字指向了目录的inode节点,分别是目录的本名和.
为什么在该目录下,每多创建一个目录,当前目录就会多一个硬链数?
新创建目录的..名字,也指向了当前目录。
Linux不允许用户自己给目录创建硬链接,只能由Linux系统自己给目录创建硬链接。用户只能给目录以外的,其它类型的文件创建硬链接。
#include
int link(const char *oldpath,const char *newplath);//原有路径名->新路径名
int unlink (const char *pathname) ;//pathname 删除硬链接的路径名
可以使用unlink创建临时文件,先用open创建一个文件,然后使用unlink删除文件的硬链接,在进程结束前还可以使用这个文件,进程结束后文件就删除了。
#include
int remove (const char *pathname) ;
功能:可以用于删除任何文件(既可以删除目录文件,也可以删除非目录文件)。删除非目录文件时,功能与unlink一样。
remove是一个库函数。它封装了unlink和rmdir这两个系统函数。remove会自动检测文件类型,如果是目录就调用rmdir删除,如果其它文件,就调用unlink删除。
#include
int rename(const char *oldpath,const char *newpath);
功能:修改文件路径名,将旧的路径名oldpath,改为新的路径名newpath。
mv就是调用rename函数实现的,看起来功能有三个(改名、移动、移动+改名),其实功能就一个,修改文件的路径名。
符号链接文件也被称为软链接文件。
使用ln -s就可以创建符号链接文件。
#include
int symlink(const char *oldpath,const char *newpath);
功能:为oldpath,创建符号连接文件newpath。
使用ln创建硬链接时,调用的是link函数。
使用ln -s创建符号链接时,调用的是symlink,sym就是符号的意思。
#include
ssize_t readlink(const char *path,char *buf,size_t bufsiz);
const char *path:符号连接文件的路径名。char *buf:存放名字的缓存。size t bufsiz:缓存的大小include <unistd.h>
char *getcwd(char *buf, size_t size) ;
char *getwd(char *buf);
buf:存放获取到的当前路径的缓存size:缓存的大小#include
int chdir(const char *path);
int fchdir(int fd) ;
切换进程当前工作目录到path或文件描述符fd指向的路径
#include
#include
int mkdir(const char *pathname,mode_t mode);
pathname:需创建目录的路径名mode:指定目录的原始权限,一般给0775#include
int rmdir(const char *pathname) ;
#include
#include
DIR *opendir(const char *name);
DIR *fdopendir(int fd);
功能:打开目录,不能使用open函数打开目录,只能使用opendir打开。
参数:
name:需打开目录的路径名
fd:文件描述符
返回值
调用成功:返回一个DIR *的指针,这个指针指向了被打开的目录,readir通过这个指针就可以读取目录的目录项。
调用失败:返回NULL,errno被设置。
#include
struct dirent *readdir(DIR *dirp) ;
功能:读取目录里的目录项。每调用一次,就读取出一条目录项。
参数
dirp: opendir打开目录时,得到的指针。
返回值:调用成功,返回指针指向struct dirent结构体的指针。这个结构体其实是定义在了头文件中。
这个结构体就是用来存放一条目录项的,调用readdir读取到目录项后,会自动开辟一个struct dirent变量来存放目录项,然后将变量的指针返回,应用程序通过这个指针,就可以访问结构体中的目录项信息(文件基本信息)。
struct dirent
{
ino_t d_ino;/*i节点编号*/
off_t d_off;/*地址偏移*/
unsigned short d_reclen;/*本条目录项的大小*/
unsigned chard_type;/*文件类型,不是所有系统都支持*/
char d_name [256]; /*文件名字*/
};
返回NULL的话有如下两种情况:
1)读到目录的末尾时,返回NULL。
2)函数调用失败时,也返回NULL,不过errno被设置。
怎么判断函数是否调用失败了呢,如果ernno==0,表示没有设置错误号,返回NULL是因为读到了文件的末尾。如果errno!=0,表示是因为函数调用出错而返回的NULL。
int main(void){
DIR *dirp = NULL;
dirp = opendir(".");
if(NULL == dirp)
{
perror("opendir fail");
exit(-1);
}
while(1){
struct dirent *direntp = NULL;
direntp = readdir(dirp);
if(direntp == NULL && errno!=0)//调用失败
{
perror( "readdir fail");
exit(-i);
}
printf("inodeID=%d,fnane=%s\n",direntp->d_ino,direntp->d_name);
if(direntp == NULL && errno == 0) break;//读到目录末尾
}
}
#include
int chmod(const char *pathname, mode_t mode);
int fchmod(int fd, mode_t mode);