程序中,经常会用到遍历文件夹、读取文件夹和读取文件目录等操作,本文就介绍Linux下操作文件目录的方法。
需求:遍历路径/home/workspace/test下所有的文件(文件夹、文件),输出其名字及大小。
代码:
#include<sys/types.h>
#include<sys/stat.h>
#include<dirent.h>
#include<string>
#include<iostream>
using namespace std;
int main()
{
DIR *pDir; //定义目录流对象
struct dirent *pDirent; //目录文件结构
struct stat info; //文件状态信息结构
string str = "/home/dingyan/test";
if((pDir = opendir(str.c_str())) == NULL) //打开目录文件流对象
{
cout<<"opendir failed!"<<endl;
}
while((pDirent = readdir(pDir)) != NULL) //读取目录文件流对象
{
string strpath = str + "/" + pDirent->d_name;
stat(strpath.c_str(),&info); //取得文件对象的属性信息
cout<<strpath<<":"<<info.st_size<<endl;;
}
return 0;
}
strpath路径下的文件列表:
程序执行输出:
/home/dingyan/test/..:4096
/home/dingyan/test/file1:0
/home/dingyan/test/.:4096
/home/dingyan/test/file3:809
/home/dingyan/test/file2:404
针对上述实例程序代码,我们先看一下结构体DIR
,以下是DIR的定义:
struct __dirstream
{
void *__fd;
char *__data;
int __entry_data;
char *__ptr;
int __entry_ptr;
size_t __allocation;
size_t __size;
__libc_lock_define (, __lock)
};
typedef struct __dirstream DIR;
可以看出DIR是一个类似于File的内部结构,它可以通过以下函数返回:
DIR *opendir(const char *pathname)
以下是一些利用该结构保存被读取的目录的信息:
struct dirent *readdir(DIR *dp);
void rewinddir(DIR *dp);
int closedir(DIR *dp);
long telldir(DIR *dp);
void seekdir(DIR *dp,long loc);
细心的读者会发现程序输出中包含了文件.
(点)和..
(点点),即当前目录和上级目录文件。那么如何区分目录文件和正常文件之间呢,那就需要对结构pdirent进行分析了,目录文件它包含了其他文件的名字以及指向与这些文件有关的信息的指针。从定义能够看出,dirent不仅仅指向目录,还指向目录中的具体文件,readdir函数同样也读取目录下的文件。已知结构pdirent的定义为:
struct dirent {
ino_t d_ino; /* inode number */
off_t d_off; /* offset to the next dirent */
unsigned short d_reclen; /* length of this record */
unsigned char d_type; /* type of file; not supported
by all file system types */
char d_name[256]; /* filename */
};
但是,该结构还是比较简单的,仅仅表示了目录文件下的文件的基本信息,还必须通过函数int stat(const char *file_name, struct stat *buf);
根据d_name获取文件的详细信息,stat的结构定义如下:
struct stat {
mode_t st_mode; //文件访问权限
ino_t st_ino; //索引节点号
dev_t st_dev; //文件使用的设备号
dev_t st_rdev; //设备文件的设备号
nlink_t st_nlink; //文件的硬连接数
uid_t st_uid; //所有者用户识别号
gid_t st_gid; //组识别号
off_t st_size; //以字节为单位的文件容量
time_t st_atime; //最后一次访问该文件的时间
time_t st_mtime; //最后一次修改该文件的时间
time_t st_ctime; //最后一次改变该文件状态的时间
blksize_t st_blksize; //包含该文件的磁盘块的大小
blkcnt_t st_blocks; //该文件所占的磁盘块
};
在结构dirent中d_type表示文件类型:
DT_BLK This is a block device.
DT_CHR This is a character device.
DT_DIR This is a directory.
DT_FIFO This is a named pipe (FIFO).
DT_LNK This is a symbolic link.
DT_REG This is a regular file.
DT_SOCK This is a Unix domain socket.
DT_UNKNOWN The file type is unknown.
至此,我们就发现通过d_type这一成员就可以对文件类型进行区分了,那么修改后的源码为:
#include<sys/types.h>
#include<sys/stat.h>
#include<dirent.h>
#include<string>
#include<iostream>
using namespace std;
int main()
{
DIR *pDir;
struct dirent *pDirent;
struct stat info;
string str = "/home/dingyan/test";
if((pDir = opendir(str.c_str())) == NULL)
{
cout<<"opendir failed!"<<endl;
}
while((pDirent = readdir(pDir)) != NULL)
{
if(pDirent->d_type == DT_REG) //增加了类型判断
{
string strpath = str + "/" + pDirent->d_name;
stat(strpath.c_str(),&info);
cout<<strpath<<":"<<info.st_size<<endl;
}
}
return 0;
}
输出结果为:
/home/dingyan/test/file1:0
/home/dingyan/test/file3:809
/home/dingyan/test/file2:404
这就是我们需要的啦。