目录文件介绍
目录也是一种文件,因此操作流程与普通文件类似,有诸如打开、关闭、定位等概念,但目录是一种特殊的文件,目录存储的数据的最小单位并不是字符,而是目录项。这使得目录跟普通文件又有区别。目录项指的是结构体struct dirent{}
,其内部保存的是文件的名称、idnode节点号等基本信息,不包含文件具体内容。
// 目录项结构体 struct dirent {ino_t d_ino; /* i-node节点号 */char d_name[256]; /* 文件名 */ };
这个结构体中可能还会有其他的属性,但是我们一般用不到,并且不同电脑环境下结构体内部字段有些差别,但是i-node节点号和文件名这两个字段一定都存在。
这里的idnode节点号对应的是一个idnode结构体变量,保存着文件的基本信息如文件大小、权限、所有者、所属组、创建时间、修改时间等,所以这个idnode号可以用来进一步查询文件的详细信息
opendir,readdir,closedir(打开,读取,关闭目录)
与文件操作类似,要操作目录,首先是打开目录获取代表目录的“目录指针”,然后读取目录的基本单元“目录项”,最后关闭目录指针释放资源。操作函数如下:
示例代码:
int main(void)
{// 打开目录,获取目录指针DIR *dp = opendir("a");// 读取每个目录项,并输出各个文件的名称struct dirent *ep;while(1){ep = readdir(dp);// 读完了if(ep == NULL){break;}printf("%s\n", ep->d_name);}
}
注意:
这里readdir函数每次读取正确的时候返回的是文件项指针,所以这里我们要使用指针变量来保存循环拿到的文件项指针。
完整代码示例
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include<sys/stat.h>
#include<sys/types.h>
#include<dirent.h>
#include<strings.h>
int main(int argc, char **argv) {if(argc!=2){printf("%s","需要提供目录\n");exit(0);}
//检测文件类型,只有目录文件才能输出目录项struct stat file_stat;bzero(&file_stat,sizeof(stat));stat(argv[1],&file_stat);if(!S_ISDIR(file_stat.st_mode)){printf("%s is NoT directory.n", argv[1]);exit(0);}//打开目录文件DIR *file_dp = opendir(argv[1]);if(file_dp == NULL){perror("opendir()failed");exit(0);}//读取目录项struct dirent *ep;while(1){ep=readdir(file_dp);if(ep==NULL){break;}printf("%s\n",ep->d_name);}return 0;
}
一个理解上易错点
打开目录并不意味着进入目录,打开目录的时候当前的进程路径并没有切换到目录文件内部,即 DIR *dp = opendir("a");这行代码并没有让我们进入到a目录里面(没有cd a),我们当前的工作路径还是在目录文件所处父目录的路径。
那我们如何来直观地感受这一点呢?上面我们的例子中输出了目录文件a下的所有文件名称,那现在我们像下图一般,在输出文件名称基础上输出文件大小。这就需要用到获取文件属性的知识,通过提供文件名,通过stat函数获取文件大小。代码如下
错误示范
我们会发现事与愿违了,不能正确输出文件的大小,原因是stat函数找不到这些文件。我们这里提供给stat函数的文件名称都是a.txt这样形式的,是进入目录文件后才可直接看到的名称,但我们打开目录并不意味着进入了目录,我们实际上根本没有进去到目录里面,所以在外面是看不到a.txt这个名字的,想要看到的话需要添加这个文件的目录前缀,比如:linux_share/a.txt,将这个字符串提供给stat函数才能得到文件属性。
这当然是个方法,可以利用字符串拼接的方式将完整的文件名称传给stat函数,但是有点过于麻烦了。我们上面的代码会出问题的原因是当前的进程路径并没有切换到目录文件内部,我们只需要进入目录文件就行了,写cd语句肯定是不行的,这里的chdir函数可以帮助我们在代码中实现cd的功能,只需要在代码中加入这一行chdir改变进程路径代码就可以了,是不是很简便。
正确示范
只需要在这里打开目录文件的时候顺便进入目录文件。就能实现将目录下的文件名称和文件大小都打印出来。真正进入目录的函数是chdir,其实就是和命令行中的cd功能一样。
chdir函数详解
文件I/O文章小结
前言:截至到今天,文件I/O系列文章已经写了七篇文章,这七篇文章带着我们从系统I/O函数——>标准I/O函数,随后我们又了解了linux中文件的存储和属性相关信息,知道了如何查看文件的各种属性,最后我们简单地谈了一下linux下如何对目录文件内容进行访问。
展望未来:接下来的文章将会继续这一个专题,只不过我们要开始联系实际,使用我们开发板来巩固我们对这些内容的学习。
标准I/O
对于我们的普通文件来说我们既可以使用系统I/O和标准I/O对文件进行操作,我们推荐使用标准I/O对普通文件操作,因为多了系统的缓冲区,减少了系统I/O调用次数,操作效率提高了。但是标准I/O一般就是简化了我们对于普通文件的操作(包含二进制文件)。对于其他类型的文件我们一帮更加推荐使用系统。
系统I/O
对于FIFO 文件、符号链接、字符设备文件、块设备文件和套接字,我们推荐使用系统I/O和一些特定函数对这些文件进行操作。不同类型文件有着对应特定函数。比如说对于LCD屏幕(通常属于字符设备文件),我们常常用open和close系统I/O打开关闭文件,再配合上特定的mmap函数对设备文件进行操作。(如 open
, read
, write
, ioctl
)
文件特定操作函数
对于目录文件来说我们用到的通常就是特定的函数对其进行操作
opendir
:打开一个目录,并返回一个指向DIR
结构的指针。readdir
:从目录流中读取下一个目录项。closedir
:关闭目录流。mkdir
:创建一个新目录。rmdir
:删除一个空目录。