zoukankan      html  css  js  c++  java
  • C/C++ 遍历目录文件,默认目录下(转载)

     

    每次遇到这样的问题总会折腾很久,到网上搜,或者查资料,弄了很多次,但就是没记住,这次写程序又遇到了,干脆就把它都弄清楚了,然后顺便在这里记录一下,以后再遇到就不用到处去找了。

            用 C/C++ 遍历目录文件主要有两种方式,分别对应在 Windows VS 环境下和 LinuxUnix 环境下的方法,它们各自所使用的函数如下:

    1. (Windows VS)_findfirst, _findnext, _findclose
    2. (LinuxUnix)opendir, readdir, closedir

    下面就来详细地说说这两种方式

    第一(_findfirst, _findnext, _findclose)

      基本流程:_findfirst-->_findnext-->_findclose

     

    (1)First Step

             _findfirst 的函数原型:

    [cpp] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. long _findfirst( char *filespec, struct _finddata_t *fileinfo );  

            它返回一个文件句柄,可以作为其他函数的参数,并将文件名匹配由 filespec 指定的模式的第一个文件的信息保存在 fileinfo 里。例如我要找某个目录下的 txt 文件,那么 fileinfo 就保存了这个目录下第一个 txt 文件的信息,这种情况下我们可以这样来调用这个函数:

    [cpp] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. long pFile = long _findfirst( "*.txt", fileinfo );  

    而用来保存文件信息的 fileinfo 是一个数据类型为 _finddata_t 的结构体,在头文件IO.H定义:

    [cpp] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. struct _finddata_t {  
    2.         unsigned    attrib;              /*文件属性*/  
    3.         time_t      time_create;         /*文件创建时间, -1 for FAT file systems */  
    4.         time_t      time_access;         /*文件最后一次访问的时间 -1 for FAT file systems */  
    5.         time_t      time_write;          /*文件最后一次写的时间*/   
    6.         _fsize_t    size;                /*文件大小*/  
    7.         char        name[_MAX_FNAME];    /*匹配的文件名,不包含目录,_MAX_FNAME在STDLIB.H中定义为256字节*/  
    8. };  

    其中文件属性可以是以下的这些值(MSDN上的说明):

    _A_ARCH(存档)

    Archive. Set whenever the file is changed, and cleared by the BACKUP command. Value: 0x20

    _A_HIDDEN(隐藏文件)

    Hidden file. Not normally seen with the DIR command, unless the /AH option is used. Returns information about normal files as well as files with this attribute. Value: 0x02

    _A_NORMAL(普通文件,没有读写限制)

    Normal. File can be read or written to without restriction. Value: 0x00

    _A_RDONLY(只读文件)

    Read-only. File cannot be opened for writing, and a file with the same name cannot be created. Value: 0x01

    _A_SUBDIR(子目录)

    Subdirectory. Value: 0x10

    _A_SYSTEM(系统文件)

    System file. Not normally seen with the DIR command, unless the /A or /A:S option is used. Value: 0x04

     

    (2)Second Step

            我们已经读取了第一个文件的信息了,那怎么读取下一个呢,这时候就轮到 _findnext 出马了,同样我们先看看其函数原型:

    [cpp] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. int _findnext( long handle, struct _finddata_t *fileinfo );  

            这个函数调用如果成功就返回0,否则返回-1。它将下一个文件名匹配 filespec 的文件的信息保存在 fileinfo 里面,handle 是调用 _findfirst 时返回的句柄。比如说我们这里的例子,要得到下一个txt文件的信息,我们可以这样调用函数

    [cpp] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. _findnext(pFile, fileinfo);  

    所以我们不断调用 _findnext 直到它返回-1就可以遍历所有的txt文件了。

     

    (3)Step Three

            函数 _findclose 就是做一些收尾工作,关闭文件句柄:

    [cpp] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. int _findclose( long handle );  

            同样地,handle 也是调用 _findfirst 时返回的句柄。

     

    (4)Final

            综上所述,遍历某个目录下指定的文件(所有文件则用*表示)可以这样写:

    [cpp] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. #include <io.h>  
    2.   
    3. int main()  
    4. {  
    5.     struct _finddata_t fileinfo;  
    6.     long hFile;  
    7.     if((hFile = _findfirst("*.txt",&fileinfo)) == -1)  
    8.         return -1;  
    9.     else {  
    10.         do {  
    11.             /*Process File*/  
    12.         }while (_findnext(hFile,&file)==0);  
    13.     }  
    14.     _findclose(hFile);  
    15.     return 0;  
    16. }  

    第二(opendir, readdir, closedir)

      基本流程:opendir-->readdir-->closedir

     

    (1)Step One

           使用这些函数我们需要包含头文件 <sys/types.h> 和 <dirent.h>。

            我们要读取目录下的文件信息,首先要打开目录,也就是要调用函数 opendir:

    [cpp] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. DIR *opendir(const char *pathname);  

            这个函数以目录的路径为参数,如果打开成功,就返回一个DIR类型的指针,相当于上面所说的句柄,用于后续函数调用;否则返回 NULL。所以如果要打开当前目录可以这样调用函数:

    [cpp] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. DIR *pDir = opendir(".");  

            这样我们就打开了目录,返回值 pDir 用于接下来函数调用的参数。

     

    (2)Step Two

            接下来就是读取文件的信息了 ,在 <dirent.h> 中定义了一个结构体 dirent ,用来保存文件信息,定义如下:

    [cpp] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. struct dirent {  
    2.     ino_t          d_ino;       /* i-inode number */  
    3.     off_t          d_off;       /* offset to the next dirent */  
    4.     unsigned short d_reclen;    /* length of this record */  
    5.     unsigned char  d_type;      /* type of file */  
    6.     char           d_name[256]; /* null-terminated filename */  
    7. };  

            这里面其实经常要用到的就是 d_type 和 d_name 这两个字段,分别表示文件类型和文件名。

            d_type 表示文件类型,其取值定义如下:

    [cpp] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. enum  
    2. {  
    3.     DT_UNKNOWN = 0,  
    4. # define DT_UNKNOWN DT_UNKNOWN  
    5.     DT_FIFO = 1,  
    6. # define DT_FIFO DT_FIFO  
    7.     DT_CHR = 2,  
    8. # define DT_CHR DT_CHR  
    9.     DT_DIR = 4,  
    10. # define DT_DIR DT_DIR  
    11.     DT_BLK = 6,  
    12. # define DT_BLK DT_BLK  
    13.     DT_REG = 8,  
    14. # define DT_REG DT_REG  
    15.     DT_LNK = 10,  
    16. # define DT_LNK DT_LNK  
    17.     DT_SOCK = 12,  
    18. # define DT_SOCK DT_SOCK  
    19.     DT_WHT = 14  
    20. # define DT_WHT DT_WHT  
    21. };  

            然后使用 readdir 这个函数来读取文件信息:

    [cpp] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. struct dirent *readdir(DIR *dp);  

            dp 为调用 opendir 时的返回值。当读取成功时,函数返回一个保存文件信息的 dirent 结构体指针,当到达目录末尾或出错时返回 NULL。每次调用该函数时读取下一个文件的信息,所以不断调用函数直到它返回 NULL,就可以遍历该目录下所有的文件:

    [cpp] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. struct dirent * ptr = readdir(pDir);  

     

    (3)Step Three

            最后这一步也是收尾工作,关闭目录:

    [cpp] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. int closedir(DIR *dp);  

            同样的,dp 为调用 opendir 时的返回值,成功时返回0,失败时返回-1。

    [cpp] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. closedir(pDir);  

     

    (4)Final

            因此,总的遍历目录文件的程序可以这样写:

    [cpp] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. #include <stdio.h>  
    2. #include <sys/types.h>  
    3. #include <dirent.h>  
    4.   
    5. int main()  
    6. {  
    7.     DIR* pDir;  
    8.     struct dirent* ptr;  
    9.     if( !(dir = opendir(".")) )  
    10.         return -1;  
    11.     while( (ptr = readdir(pDir)) != 0 )  
    12.     {  
    13.         /*Processing File*/  
    14.     }  
    15.     closedir(pDir);  
    16.     return 0;  
    17. }  

    总结

            一般来说,第一种方法只能在 Windows VS 环境下用,而第二种方法只能在 Linux/Unix 环境下使用。因为在用 VS 写程序的过程中想用第二种方法看看能不能用,结果是找不到头文件 <dirent.h>,而且从结构体 dirent 的定义中我们就可以看出,它只能在 Linux 下使用,因为 dirent 的定义中有个字段是表示文件的 i-node number,这个恰恰是在Linux 的文件管理中才有的。当在 Linux 想用第二种方法时则找不到头文件 <io.h>。但网络上可能有一些方法可以两种方法在两个平台上都可以使用,这个我倒没有去搜索相关的资料,如果大家有什么好的办法,可以分 享一下。上面的两个程序我都已经测试过了,用的是 VS2012 和 Ubuntu。

            另外,由上面的解说可以看到,在 Windows 下可以很容易地读取某一类型的文件的信息(比如 txt 文件),但在 Linux 下则需要多花些功夫(比如要查看 txt 文件,你得读取文件信息然后再判断文件扩展名是不是 .txt)。

    扩展:

    #ifndef WIN32

    DIR *pDIR = NULL;

    struct dirent *pFILE=NULL;

    1.打开目录根据参数

    if(!(pDIR = opendir(LocalPath)))

    {

    }

    2.便利目录

    while((pFILE = readdir(pDIR))!=NULL)

    {

    }

    3.close dir

    closedir(pDIR);

    #endif

  • 相关阅读:
    101. Symmetric Tree(js)
    100. Same Tree(js)
    99. Recover Binary Search Tree(js)
    98. Validate Binary Search Tree(js)
    97. Interleaving String(js)
    96. Unique Binary Search Trees(js)
    95. Unique Binary Search Trees II(js)
    94. Binary Tree Inorder Traversal(js)
    93. Restore IP Addresses(js)
    92. Reverse Linked List II(js)
  • 原文地址:https://www.cnblogs.com/cyblogs/p/9102854.html
Copyright © 2011-2022 走看看