在Linux下和Windows下遍历目录的方法及如何达成一致性操作
|
最近因为测试目的需要遍历一个目录下面的所有文件进行操作,主要是读每个文件的内容,只要知道文件名就OK了。在Java中直接用File类就可以搞定,因为Java中使用了组合模式,使得客户端对单个文件和文件夹的使用具有一致性,非常方便。但在C中就不一样了,而且在不同的平台下使用方法也不同。在Linux下实现该功能就非常方便,因为自带有API库,几个函数用起来得心应手(虽然有些小问题,后面说),在Windows下实现就不是那么方便,虽然也有自己的API,但用法有些晦涩难懂,因为没有封装起来,需要自己一步一步进行操作,因为用的是Windows API库函数所以如果对Windows编程不熟悉的话,照搬网上的代码错了也不易调试。为此,我把这些操作都封装成类似Linux下的库函数,一方面简化透明了操作,另一方面(也许更重要)就是移植性,这样将包含该功能的程序从Windows上移植到Linux下就无需改动代码了(删掉实现封装的文件,因为Linux下自带了),当然从Linux下移植到Windows下同样方便(增加实现封装的文件即可),这就是所谓的OCP原则吧(开放封闭原则,具体见:程序员该有的艺术气质—SOLID原则)。好了,首先看下Linux下是如何实现这个功能的。 Linux下实现目录操作的API函数都在头文件dirent.h中,截取部分该文件内容如下:
/** structure describing an open directory. */
typedef struct _dirdesc {
int dd_fd; /** file descriptor associated with directory */
long dd_loc; /** offset in current buffer */
long dd_size; /** amount of data returned by getdirentries */
char *dd_buf; /** data buffer */
int dd_len; /** size of data buffer */
long dd_seek; /** magic cookie returned by getdirentries */
long dd_rewind; /** magic cookie for rewinding */
int dd_flags; /** flags for readdir */
struct pthread_mutex *dd_lock; /** lock */
struct _telldir *dd_td; /** telldir position recording */
} DIR;
typedef void * DIR;
DIR *opendir(const char *);
DIR *fdopendir(int);
struct dirent *readdir(DIR *);
void seekdir(DIR *, long);
long telldir(DIR *);
void rewinddir(DIR *);
int closedir(DIR *);
struct dirent
{
long d_ino; /* inode number*/
off_t d_off; /* offset to this dirent*/
unsigned short d_reclen; /* length of this d_name*/
unsigned char d_type; /* the type of d_name*/
char d_name[1]; /* file name (null-terminated)*/
};
关键部分就是DIR这个结构体的定义,包括文件描述符、缓冲区偏移、大小、缓冲区内容等,下面定义的就是具体的目录操作函数了,有打开目录、读目录、重置读取位置、关闭目录等,这里我所需要的就是打开、读和关闭这三个最基本的目录操作,下面是使用例子:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#define MAX_LEN 65535
int main(void)
{
DIR *dir;
struct dirent *ptr;
char *flow[MAX_LEN];
int num = 0, i = 0;
if ((dir=opendir("./data")) == NULL)
{
perror("Open dir error...");
exit(1);
}
// readdir() return next enter point of directory dir
while ((ptr=readdir(dir)) != NULL)
{
flow[num++] = ptr->d_name;
// printf("%sn", flow[num - 1]);
}
for(i = 0; i < num; i++)
{
printf("%sn", flow[i]);
}
closedir(dir);
}
运行结果如下:
一看这结果就不对,输出的都是同一个文件名(最后一个文件的文件名), 哪里出了问题呢?将代码中// printf("%sn", flow[num - 1]);这行注释去掉再运行,发现注释处输出的是正确的,两者都是输出的flow数组元素怎么结果不一样呢?经过调试发现是flow[num++] = ptr->d_name;这句代码的问题,因为这是引用拷贝(地址拷贝),所有的flow元素全部指向同一个对象ptr->d_name,虽然ptr->d_name对象每次的内容不同(也就是前面正确输出的原因),但所有内容都共享一个地址,用一个简单的图说明就是: 当然这个问题也比较好解决,也是比较常见的问题,用字符串拷贝或内存拷贝就行了,给flow每个元素重新申请一块内存。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#define MAX_LEN 65535
int main(void)
{
DIR *dir;
struct dirent *ptr;
char *flow[MAX_LEN];
int num = 0, i = 0;
if ((dir=opendir("./data")) == NULL)
{
perror("Open dir error...");
exit(1);
}
// readdir() return next enter point of directory dir
while ((ptr=readdir(dir)) != NULL)
{
flow[num] = (char*)malloc(sizeof(char));
strcpy(flow[num], ptr->d_name);
num++;
}
for(i = 0; i < num; i++)
{
printf("%sn", flow[i]);
}
closedir(dir);
}
最终结果就正确了。
二、Windows下遍历目录的方法 在Windows下就比较麻烦了,所要用到的函数都在windows.h中,Windows编程本来就比较繁琐,下面就不一一介绍所用到的函数了,直接给出封装的过程。 1. 首先模拟Linux下自带的头文件dirent.h (编辑:佛山站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |



