PG目录操作封装——dirent一:postgresql-8.4.1\src\port\dirent.c

主要用于对目录数据结构和目录操作函数的封装

  头文件的路径如下所示:/src/include/port/win32_msvc/dirent.h。该文件主要是win32 native目录操作函数的封装。从源代码目录接口可以看出该文件主要作用是针对win32_msvc的移植文件,这里的port就是移植的意思。这些封装主要依靠DIR和dirent两个结构体来存储信息以及和其他文件进行交互。DIR中有指向char的指针dirname,用于存放目录名的char数组,dirent结构体和handle句柄。dirent结构体包含了存放inodes的d_ino和不需要使用的d_reclen(这连个数据结构在windows上都不需要)以及文件名数组和文件名长度。

1 struct DIR
2 {
3 char    *dirname;
4 struct dirent ret;    /* Used to return to caller */
5 HANDLE    handle;
6 };
1 struct dirent
2 {
3 long    d_ino;
4 unsigned short d_reclen;
5 unsigned short d_namlen;
6 char    d_name[MAX_PATH];
7 };

由头文件可以看出主要提供三个函数,即opendir、readdir和closedir三个函数。它们主要的传入传出参数和上述两个结构体相关。下面我们就详细分析这三个函数的详细代码。

 1 /*
 2 * Headers for port/dirent.c, win32 native implementation of dirent functions
 3 *
 4 * $PostgreSQL: pgsql/src/include/port/win32_msvc/dirent.h,v 1.3 2006/10/04 00:30:10 momjian Exp $
 5 */
 6 
 7 #ifndef _WIN32VC_DIRENT_H
 8 #define _WIN32VC_DIRENT_H
 9 struct dirent
10 {
11 long    d_ino;
12 unsigned short d_reclen;
13 unsigned short d_namlen;
14 char    d_name[MAX_PATH];
15 };
16 
17 typedef struct DIR DIR;
18 
19 DIR    *opendir(const char *);
20 struct dirent *readdir(DIR *);
21 int    closedir(DIR *);
22 
23 #endif

opendir打开目录函数,传入参数为目录路径数组。调用win32的GetFileAttributes函数,并对返回值进行检测。使用malloc申请DIR结构体,对dirname和handle信息进行填充,如果路径末尾没有/或\\,则直接追加\\,最后加上*号,代表所有该目录下的文件。将handle设置为INVALID_HANDLE_VALUE,并将dirent结构体ret中的d_ino和d_reclen设置为0(在Windows下无效)。

 1 DIR *
 2 opendir(const char *dirname)
 3 {
 4     DWORD        attr;
 5     DIR           *d;
 6 
 7     /* Make sure it is a directory */
 8     attr = GetFileAttributes(dirname);
 9     if (attr == INVALID_FILE_ATTRIBUTES)
10     {
11         errno = ENOENT;
12         return NULL;
13     }
14     if ((attr & FILE_ATTRIBUTE_DIRECTORY) != FILE_ATTRIBUTE_DIRECTORY)
15     {
16         errno = ENOTDIR;
17         return NULL;
18     }
19 
20     d = malloc(sizeof(DIR));
21     if (!d)
22     {
23         errno = ENOMEM;
24         return NULL;
25     }
26     d->dirname = malloc(strlen(dirname) + 4);
27     if (!d->dirname)
28     {
29         errno = ENOMEM;
30         free(d);
31         return NULL;
32     }
33     strcpy(d->dirname, dirname);
34     if (d->dirname[strlen(d->dirname) - 1] != / &&
35         d->dirname[strlen(d->dirname) - 1] != \\)
36         strcat(d->dirname, "\\");        /* Append backslash if not already
37                                          * there */
38     strcat(d->dirname, "*");    /* Search for entries named anything */
39     d->handle = INVALID_HANDLE_VALUE;
40     d->ret.d_ino = 0;            /* no inodes on win32 */
41     d->ret.d_reclen = 0;        /* not used on win32 */
42 
43     return d;
44 }

closedir关闭目录文件,传入参数为DIR的指针。如果handle不为INVALID_HANDLER_VALUE则需要关闭句柄,最后释放申请的存放目录名的空间以及输入的DIR结构体的空间。

1 int
2 closedir(DIR *d)
3 {
4     if (d->handle != INVALID_HANDLE_VALUE)
5         FindClose(d->handle);
6     free(d->dirname);
7     free(d);
8     return 0;
9 }

readdir函数利用opendir处理的DIR结构体中的handle信息,更新DIR结构体中dirent结构体的数据,并将其返回。主要逻辑分两块:如果handle为INVALID_HANDLE_VALUE,则说明刚调用完readdir函数,还没有真正处理该目录下的文件,在这种情况下,使用FIndFirstFile获取第一个文件的handle;如果handle不为INVALID_HANDLE_VALUE,说明已经获取过文件了,则使用FindNextFile函数获取下一个文件的句柄。最终根据获取的文件名和文件名长度更新一下dirent结构体。

 1 struct dirent *
 2 readdir(DIR *d)
 3 {
 4     WIN32_FIND_DATA fd;
 5 
 6     if (d->handle == INVALID_HANDLE_VALUE)
 7     {
 8         d->handle = FindFirstFile(d->dirname, &fd);
 9         if (d->handle == INVALID_HANDLE_VALUE)
10         {
11             errno = ENOENT;
12             return NULL;
13         }
14     }
15     else
16     {
17         if (!FindNextFile(d->handle, &fd))
18         {
19             if (GetLastError() == ERROR_NO_MORE_FILES)
20             {
21                 /* No more files, force errno=0 (unlike mingw) */
22                 errno = 0;
23                 return NULL;
24             }
25             _dosmaperr(GetLastError());
26             return NULL;
27         }
28     }
29     strcpy(d->ret.d_name, fd.cFileName);        /* Both strings are MAX_PATH
30                                                  * long */
31     d->ret.d_namlen = strlen(d->ret.d_name);
32     return &d->ret;
33 }

 

下面使用window的api:FIndFirstFile和FindNextFile做一个小demo测试一下:

FindFirstFile()用于获得指定目录的第一个文件,参数为lpFileName 用于指定搜索目录和文件类型,可以用通配符,初次使用需要注意 \ 需要用转义字符表达。即:D:\\C++ 6.0\\;
lpFindFileData 用于保存搜索得到的文件信息。FindFirstFile() 返回HANDLE类型,为下一次搜索提供信息。当搜索失败时,返回INVALID_HANDLE_VALUE

1     HANDLE WINAPI FindFirstFile(
2         _In_   LPCTSTR lpFileName,
3         _Out_  LPWIN32_FIND_DATA lpFindFileData
4     );

FindNextFile() 顾名思义,用于搜索下一个文件,当不存在下一个文件,即搜索完毕后,返回false。hFindFile 上一次FindFirstFile或FindNextFile得到的HANDLE;
lpFindFileData 用于保存搜索得到的文件信息。

1     BOOL WINAPI FindNextFile(
2         _In_   HANDLE hFindFile,
3         _Out_  LPWIN32_FIND_DATA lpFindFileData
4     );

通常,最初的两次搜索得到的文件名为:"." 、"..",分别代表当前目录和上级目录。写代码时需要注意。

 1     HANDLE hFile;
 2     LPCTSTR lpFileName = L".\\*.*";    //指定搜索目录和文件类型,如搜索d盘的音频文件可以是"D:\\*.mp3"
 3     WIN32_FIND_DATA pNextInfo;    //搜索得到的文件信息将储存在pNextInfo中;
 4     hFile = FindFirstFile(lpFileName,&pNextInfo);//请注意是 &pNextInfo , 不是 pNextInfo;
 5     if(hFile == INVALID_HANDLE_VALUE)
 6     {
 7         //搜索失败
 8         exit(-1);
 9     }
10     while(FindNextFile(hFile,&pNextInfo))
11     {
12         if(pNextInfo.cFileName[0] == .)//过滤.和..
13            continue;
14         cout<<"得到文件:"<<pNextInfo.cFileName<<endl;
15     }

 

既然是移植,我们来看看Linux下的opendir和readdir以及closedir函数。读取目录的库函数均以getdents系统调用(未纳入SUSv3规范)为基础,但其接口更易于使用。Linux还提供了readdir(2)系统调用(相对于此处描述的readdir(3)库函数),所执行的任务类似于getdents(),也因之而遭废止。

opendir函数打开一个目录,并返回指向该目录的句柄,供后续调用。opendir函数打开由dirpath指定的目录,并返回指向DIR类型结构的指针。该结构即所谓目录流(directory stream),亦即调用者传递给下述其他函数的句柄。一旦从opendir返回,则将目录流指向目录列表的首条记录。

1 #include <dirent.h>
2 DIR *opendir(const char *dirpath);
3 Returns directory stream handle, or NULL on error

readdir函数从一个目录流中读取连续的条目。每调用一次,就会从dirp所指代的目录流中读取下一条目录条目,并返回一个指针,指向经静态分配而得到的dirent类型结构,内含与条目相关的如下信息,每次调用都会覆盖该结构。下面对dirent的定义略去了各种非标准字段,比如d_type字段(DT_REG普通文件、DT_DIR目录、DT_LNK符号链接、DT_FIFO)

1 #inclue <dirent.h>
2 struct dirent * readdir(DIR *dirp)
3 Returns pointer to a statically allocated structure describing next directory entry, or NULL on end-of-directory or error
4 
5 struct dirent{
6   ino_t d_ino;    // File i-node number
7   char d_name[];  // Null-terminated name of file
8 }                  

路径名由之前调用opendir时指定的dirpath参数与/字符以及d_name字段的返回值拼接组成。readdir返回时并未对文件名进行排序,而是按照文件在目录中出现的天然次序(这取决于文件系统向目录添加文件时所遵循的次序,及其在删除文件后对目录列表中空隙的填补方式)。一旦遇到目录结尾或是出错,readdir将返回NULL,针对后一种情况,还会设置errno以示具体错误。

1 errno = 0;
2 direntp = readdir(dirp);
3 if(direntp == NULL){
4   if(errno != 0){
5     // Handle error
6   }else{
7     // We reached end of directory
8   }
9 }

closedir函数由dirp指代、处于打开状态的目录流关闭,同时释放流所使用的资源

1 #include <dirent.h>
2 int closedir(DIR *dirp);
3 Returns 0 on success or -1 on error

 

PG目录操作封装——dirent一:postgresql-8.4.1\src\port\dirent.c

上一篇:mysql登录报错:mysql: error while loading shared libraries: libncurses.so.5: cannot open shared object file: No such file or directory


下一篇:MySQLWindows配置文件