C/C++遍历目录下的所有文件(Windows/Linux篇,超详细)

本文可转载,转载请注明出处:http://www.cnblogs.com/collectionne/p/6815924.html

 

前面的一篇文章我们讲了用Windows API遍历一个目录下的所有文件,这次我们讲用一种Windows/Linux通用的方法遍历一个目录下的所有文件。

 

Windows/Linux的IDE都会提供一个头文件——<io.h>。看名字,似乎是关于I/O的,但是实际上它还提供了类似于WIN32_FIND_DATA、FindFirstFile()、FindNextFile()和FindClose()的查找文件的功能。

 

_finddata_t结构

 

_finddata_t结构用来记录查找到的文件的信息。实际上有_finddata32_t、_finddata32i64_t、_finddata64i32_t、_finddata64_t、_wfinddata32_t、_wfinddata32i64_t、_wfinddata64i32_t、_wfinddata64_t八个结构,但都只是在32位/64位整数和字符类型上有所区别,但整体上相同。大致定义如下(MSDN):

 

struct _finddata_t
{
    unsigned attrib;
    size_t time_create;
    size_t time_access;
    size_t time_write;
    _fsize_t size;
    char name[_MAX_PATH];
};

 

对于不同的_finddata_t结构,time_create、time_access和time_write的类型为_time32_t或_time64_t,size的类型为_fsize_t或__int64,name为char[_MAX_PATH]或wchar_t[_MAX_PATH]。

 

attrib

 

unsigned类型,文件属性。

 

time_create

 

_time32_t/_time64_t类型,文件创建时间(FAT文件系统为-1)。以UTC格式存储,如果需要转换成当地时间,使用localtime_s()。

 

time_access

 

_time32_t/_time64_t类型,文件最后一次被访问的时间(FAT文件系统为-1)。以UTC格式存储,如果需要转换成当地时间,使用localtime_s()。

 

time_write

 

_time32_t/_time64_t类型,文件最后一次被写入的时间。以UTC格式存储,如果需要转换成当地时间,使用localtime_s()。

 

size

 

_fsize_t/__int64类型,文件的长度(以字节为单位)。

 

name

 

char[_MAX_PATH]/wchar_t[_MAX_PATH]类型,文件/目录名,不包含路径。

 

对于不支持文件创建时间、文件上一次访问时间的文件系统,time_create和time_access为-1。

 

_MAX_PATH在stdlib.h中被定义为260。

 

一般_finddata_t被定义为_finddata32_t/_finddata64i32_t,_wfinddata_t被定义为_wfinddata32_t/_wfinddata64i32_t。为方便,下文中将_finddata_t和_wfinddata_t统称为_finddata_t。

 

文件属性常量

 

一个文件/目录可以有多种属性,每种属性可以是下面列出的属性之一。

 

_A_ARCH

 

档案。文件被BACKUP指令改变或清除时被设置。值:0x20。

 

_A_HIDDEN

 

隐藏。使用DIR指令一般看不到,除非使用/AH选项。值:0x02。

 

_A_NORMAL

 

普通。文件没有更多属性被设置,可以没有限制地被读或写。值:0x00。

 

_A_RDONLY

 

只读。不能以“写”为目的打开该文件,并且不能创建同名的文件。值:0x01。

 

_A_SUBDIR

 

子目录。值:0x10。

 

_A_SYSTEM

 

系统文件。使用DIR指令一般看不见,除非使用/A或/A:S选项。值:0x04。

 

要检查x是否含有某个属性a,可以用x & a进行检查。指定多个属性可以使用按位or运算符,例如_A_SYSTEM |  _A_RDONLY | _A_HIDDEN。

 

通配符(wildcards)

 

遍历文件目录时需要使用通配符,详见我的另一篇文章

 

_findfirst()/_findnext()/_findclose()函数

 

_findfirst()函数

 

intptr_t _findfirst(
    const char * filespec,
    struct _finddata_t *fileinfo
);

 

实际上_findfirst()有10个版本,这里只列出一个。

 

filespec

 

const char */const wchar_t *类型,目标文件说明(可包含通配符)。

 

fileinfo

 

_finddata_t *类型,函数将会填入文件/目录信息。

 

返回值

 

如果成功,返回一个唯一的搜索句柄标识一个或一组和filespec说明匹配的文件,可以用于接下来的_findnext()和_findclose()函数。否则_findfirst()返回-1。注意,intptr_t并不是指针类型,只是int或__int64的typedef。

 

_findnext()函数

 

int _findnext(
    intptr_t handle,
    struct _finddata_t *fileinfo
);

 

handle

 

intptr_t类型,搜索句柄。

 

fileinfo

 

_finddata_t *类型,函数将会填入文件/目录信息。

 

返回值

 

如果成功,返回0,否则返回-1。如果没有更多能够找到的文件了,也会导致失败。

 

_findclose()函数

 

int _findclose(
    intptr_t handle
);

 

关闭搜索句柄并释放相应的资源。

 

handle

 

搜索句柄。

 

返回值

 

成功返回0,失败返回-1。

 

程序代码

 

1. 遍历目录下的所有文件

 

#include <iostream>
#include <cstring>        // for strcat()
#include <io.h>
using namespace std;

void listFiles(const char * dir);

int main()
{
    char dir[200];
    cout << "Enter a directory (ends with \'\\\'): ";
    cin.getline(dir, 200);

    strcat(dir, "*.*");        // 在要遍历的目录后加上通配符
    listFiles(dir);

    return 0;
}

void listFiles(const char * dir)
{
    intptr_t handle;
    _finddata_t findData;

    handle = _findfirst(dir, &findData);    // 查找目录中的第一个文件
    if (handle == -1)
    {
        cout << "Failed to find first file!\n";
        return;
    }

    do
    {
        if (findData.attrib & _A_SUBDIR
            && strcmp(findData.name, ".") == 0
            && strcmp(findData.name, "..") == 0
            )    // 是否是子目录并且不为"."或".."
            cout << findData.name << "\t<dir>\n";
        else
            cout << findData.name << "\t" << findData.size << endl;
    } while (_findnext(handle, &findData) == 0);    // 查找目录中的下一个文件

    cout << "Done!\n";
    _findclose(handle);    // 关闭搜索句柄
}

 

程序遍历目录下的所有文件/目录,如果是文件则输出文件大小。

 

注意_findnext()函数成功返回0,因此要加上==0或!=-1进行判断,不能省略。

 

此外还有一个值得注意的地方:

 

if (findData.attrib & _A_SUBDIR
    && strcmp(findData.name, ".")
    && strcmp(findData.name, "..")
)
...

 

使用_findfirst()、_findnext()进行搜索时,可能会得到"."和".."两个文件夹名。这两个值可以忽略。

 

2. 遍历目录中的所有文件

 

注意是“目录中”而不是“目录下”,这个程序将会遍历一个目录里包含的所有文件。

 

#include <iostream>
#include <cstring>        // for strcpy(), strcat()
#include <io.h>

using namespace std;

void listFiles(const char * dir);

int main()
{
    char dir[200];
    cout << "Enter a directory: ";
    cin.getline(dir, 200);

    listFiles(dir);

    return 0;
}

void listFiles(const char * dir)
{
    char dirNew[200];
    strcpy(dirNew, dir);
    strcat(dirNew, "\\*.*");    // 在目录后面加上"\\*.*"进行第一次搜索

    intptr_t handle;
    _finddata_t findData;

    handle = _findfirst(dirNew, &findData);
    if (handle == -1)        // 检查是否成功
        return;

    do
    {
        if (findData.attrib & _A_SUBDIR)
        {
            if (strcmp(findData.name, ".") == 0 || strcmp(findData.name, "..") == 0)
                continue;

            cout << findData.name << "\t<dir>\n";

            // 在目录后面加上"\\"和搜索到的目录名进行下一次搜索
            strcpy(dirNew, dir);
            strcat(dirNew, "\\");
            strcat(dirNew, findData.name);

            listFiles(dirNew);
        }
        else
            cout << findData.name << "\t" << findData.size << " bytes.\n";
    } while (_findnext(handle, &findData) == 0);

    _findclose(handle);    // 关闭搜索句柄
}

 

posted @ 2017-05-06 10:42  collectionne  阅读(101913)  评论(6编辑  收藏  举报