我正在写一个C程序,
void printdir (char*);
int main () {
printf ("Directory scan of /home: \n");
printdir ("/home/fahad/");
exit (0);
}
void printdir (char *dir) {
struct dirent *entry;
DIR *dp = opendir (dir);
if (dp == NULL) {
fprintf (stderr, "Cannot open dir:%s\n", dir);
return;
}
chdir (dir);
while ((entry = readdir(dp)) != NULL)
printf ("%s\n",entry -> d_name);
closedir (dp);
}
有趣的是,它以意想不到的方式显示输出。
考虑到在UNIX
中创建目录时的事实。前两个条目在此目录中创建,一个是.
,另一个是..
。所以基本上他们的inode
数字应该小于通过mkdir ()
或open ()
创建的目录条目(分别用于目录和文件)。
我的问题是,readdir ()
系统调用以什么顺序读取目录条目?因为我不会先输入.
和..
。
为什么会这样?
答案 0 :(得分:3)
尝试跳过“。”和“......”条目如下:
DIR* dirp;
struct dirent *dp=NULL;
char* fname;
if( !(dirp=opendir(dname)) ) {
int ec=errno;
printf("completed:-1:cannot opendir %s (%d)\n",dname,ec);
return(-1);
}
while ((dp = readdir(dirp)) != NULL) {
if( strcmp(dp->d_name,".")==0 ) continue;
if( strcmp(dp->d_name,"..")==0 ) continue;
fname=dp->d_name;
sprintf(pathname,"%s/%s",dname,fname);
}
请参阅this answer,其中指出由于订单未被声明为可预测,因此不应假设任何订单。上面的代码将给出一个如何处理(避免)这些条目的示例(在遍历目录层次结构的典型用例中)。订单可能基于目录inode中出现的文件的顺序。
答案 1 :(得分:2)
readdir()
不会以任何特定顺序返回条目。正如其他人所提到的,订单将取决于所讨论的特定文件系统。
例如,Berkeley UFS文件系统使用未排序的链接列表。请参阅http://ptgmedia.pearsoncmg.com/images/0131482092/samplechapter/mcdougall_ch15.pdf第744页的direct
结构说明。目录的二进制内容由可变长度记录流组成,每个记录包含inode编号,记录长度,字符串长度(文件名)和字符串数据本身。 readdir()
通过遍历链表(使用记录长度来了解每条记录相对于前一条记录的开始位置)并返回它找到的任何内容来工作。
通常不会优化记录列表,因此文件名按创建文件的顺序显示在列表中(或多或少)。但不完全是,因为如果它们足够小以适合,那么孔(由删除的文件产生)将填充新的文件名。
现在,并非所有文件系统都以UFS的方式表示目录。将目录数据保存在二叉树中的文件系统可以选择将readdir()
实现为该树的有序遍历,该树将呈现按其用作树的键的任何属性排序的文件。或者它可能使用预订遍历,它不会按排序顺序返回记录。
由于应用程序无法知道文件系统实现的性质(并且每个已安装的卷都可能使用不同的文件系统),因此应用程序不应该假设任何关于文件系统的顺序readdir()
返回的条目。如果他们要求对条目进行排序,他们必须将整个目录读入内存并进行自己的排序。
这就是为什么,例如,ls
命令在针对大目录运行时可能需要很长时间才能显示输出。它需要对整个名称列表进行排序(并确定最长的名称,以便计算列宽),然后才能显示任何输出。这也是ls -1U
(在一列中禁用排序和显示)将立即在这些目录上产生输出的原因。
答案 2 :(得分:2)
在此目录中创建前两个条目。 ...其他是...所以基本上他们的inode数量应该小于通过mkdir()或open()创建的目录条目(分别用于目录和文件)。
是的,您对inode编号的理解是正确的。为了验证这一点,我们可以写 简单的c ++程序,用于在地图中存储inode / name。
std::map<ino_t, std::string> entries;
std::pair<ino_t, std::string> en;
while ((entry = readdir(dp)) != NULL) {
en.first = entry->d_ino;
en.second = entry->d_name;
entries.insert(en);
printf ("%s\n",entry -> d_name);
}
"entries in GDB"
================
[5114862] = "..",
[5114987] = ".",
[5115243] = "taop",
[5115623] = "c++11_study",
[5115651] = "volume-3",
[5115884] = "gtkmm",
[5116513] = "basic",
[5116733] = "program",
[5116794] = "bakwas",
[5116813] = "a.out",
[5116818] = "foo",
这样我们就可以验证inode数量的顺序和“。” &安培; “......”不到 其他目录&amp;文件条目。
我的问题是,readdir()系统调用以什么顺序读取目录条目?因为我没有先得到谁。并且......为什么会这样?
来自本书 “由W. Richard Stevens在UNIX®环境中进行高级编程” , 我们可以得到以下内容:
opendir函数初始化事物,以便第一个readdir读取目录中的第一个条目。目录中条目的顺序取决于实现,通常不是按字母顺序排列的。所以他们的订单没有定义,对于上面的程序,readdir()按以下顺序给出。
Output from readdir()
=====================
c++11_study
taop
volume-3
basic
.
gtkmm
foo
program
a.out
..
bakwas