C++获取文件夹和文件信息

介绍

    本文的目的是介绍C++中如何通过_findfirst,和_findclose方法来查找文件夹中所有子文件夹和文件.本文还讨论了使用SHGetFileInfo函数和结构体来获取文件/文件夹的详细信息。

paragraph 库和头文件

    为了使用_findfirst,_findnext和_findclose方法,需要包含头文件:

#include <io.h>

    io.h中包含大量对文件系统进行底层操作的函数。

    本文例子中使用了字符串宏,因此还需要包含头文件:

#include <AtlBase.h>

paragraph 函数族和宏定义

    为了适应各种不同的编译环境,Microsoft往往对C++函数给出多个版本的实现。_findfirst,_findnext和以及_finddata_t根据以下编译环境的不同给出了多种实现

  1. 采用多字符集或Unicode字符集
  2. 采用32位时间或64位时间
  3. 采用32位文件长度或64位文件长度

    所有函数实现列表如下:

MBCS/
Unicode
time typefile length typeFunctions
MBCS32bit32bit_findfirst32, _findnext32, _finddata32_t
MBCS32bit64bit_findfirst32i64, _findnext32i64, _finddata32i64_t
MBCS64bit32bit_findfirst64i32, _findnext64i32, _finddata64i32_t
MBCS64bit64bit_findfirst64, _findnext64, __finddata64_t
Unicode32bit32bit_wfindfirst32, _wfindnext32, _wfinddata32_t
Unicode32bit64bit_wfindfirst32i64, _wfindnext32i64, _wfinddata32i64_t
Unicode64bit32bit_wfindfirst64i32, _wfindnext64i32, _wfinddata64i32_t
Unicode64bit64bit_wfindfirst64, _wfindnext64, _wfinddata64_t

    _findclose方法只有一种实现。

    C++同时提供了大量的宏,来保证我们的代码即使不经过修改,也可以适应不同的编译环境,这些宏全部或部分根据下面2个编译环境来决定最终被替换成哪个函数:

  1. 在_UNICODE被定义时,使用支持UNICODE的实现,在_MBCS被定义或2者都没有被定义时,使用支持MBCS的实现。
  2. 在_USE_32BIT_TIME_T 被定义时使用支持32bit时间类型的函数,在其没有被定义时采用64bit时间类型的函数。

    下面列出_findfirst几种常用的宏:

不同编译环境时对应的函数
_findfirst_findfirst32
_tfindfirst_MBCS 定义,_USE_32BIT_TIME_T 定义时:            _findfirst32
_MBCS 定义,_USE_32BIT_TIME_T NOT 定义时:      _findfirst64i32
_UNICODE 定义,_USE_32BIT_TIME_T 定义时:        _wfindfirst32
_UNICODE 定义,_USE_32BIT_TIME_T NOT 定义时: _wfindfirst64i32
_tfindfirst32_MBCS 定义时:      _findfirst32
_UNICODE 定义时: _wfindfirst32
_tfindfirst64_MBCS 定义时:       _findfirst64
_UNICODE 定义时:  _wfindfirst64

    为了让我们的代码有很好的兼容性,下面我们都采用_tfindfirst64宏来讲解,_findfirst的其他宏和函数在用法上与其是一致的。其他用到的函数也都是宏,保证代码在多字符集和Unicode字符集下都不需修改即能通过编译。

paragraph 函数用法

intptr_t _tfindfirst64 (LPCTSTR filespec,struct _tfinddata64_t *fileinfo)
 
int _tfindnext64( intptr_t handle, struct _tfinddata64_t *fileinfo );
 
int _findclose(intptr_t handle);
 
上面的函数定义中,_tfindfirst64,_tfinddata64_t,_tfindnext64,LPCTSTR都是宏,LPCTSTR是字符串宏,在多字符集时等于const char*,Unicode字符集是等于const wchar*。 
  1. _tfindfirst64函数: 该函数用于得到指定路径filespec下的第一个文件(或者文件夹), filespec支持通配符,例如"c:/*.*”指查找C盘所有的文件和子目录。 fileinfo由函数填充后返回,记录第一个文件(或文件夹)的信息,返回值是一个唯一性搜索句柄,用来传递给_tfindnext64查找下一个文件,或者传递给_findclose来关闭该句柄。如果调用失败,返回值等于-1.
  2. _tfindnext64函数: 该函数用于搜索下一个文件(或文件夹),参数handle是之前调用_tfindfirst64返回的句柄,fileinfo由函数填充后返回,记录当前文件(或文件夹)的信息,如果查找成功,返回值为0,否则为-1. 我们一般都采用do…while循环不断调用_tfindnext64函数来遍历当前目录下所有的子目录和文件,直到返回-1时结束。
  3. _findclose函数: 用于结束查找时关闭句柄,参数handle是之前调用_tfindfirst64返回的句柄。
  4. _tfinddata64_t 结构体: 我们以_wfinddata64_t 为例,其有如下定义
struct _wfinddata64_t {
        unsigned    attrib;
        __time64_t  time_create;    /* -1 for FAT file systems */
        __time64_t  time_access;    /* -1 for FAT file systems */
        __time64_t  time_write;
        __int64     size;
        wchar_t     name[260];
};

    time_create,time_access,time_write分别指创建时间,最近访问时间,和最后修改时间;name为文件(或文件夹)名称;attrib描述的文件的系统属性,它由多个attributes组合而成,在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 /AS option is used. Value: 0x04

    _A_SUBDIR属性表示该对象是一个子目录,我们可以探测这个位是否被设置来判断这是一个文件还是文件夹。这样,我们就可以采用递归的办法,来获取每个子目录下的文件信息。

    下面的是一段演示代码,采用递归的方法,获取当前目录和所有子目录下文件的信息,并把它们的文件属性打印出来,并把每个文件的全路径存储在一个vector结构中。

#include <io.h>
#include <vector>
#include <AtlBase.h>
#include <time.h>
 
using namespace std;
void GetAllFileInfo(LPCTSTR path, vector<LPCTSTR> &filesPathVector)
{
    //find the first file
    _tfinddata64_t c_file;
    intptr_t hFile;
    TCHAR root[MAX_PATH];
    _tcscpy(root,path);
    _tcscat(root,_T("//*.*"));
    hFile=_tfindfirst64(root,&c_file);
    if( hFile  == -1)
        return;
 
    //search all files recursively.
    do
    {
        if(_tcslen(c_file.name)==1&&c_file.name[0]==_T('.')
            ||_tcslen(c_file.name)==2&&c_file.name[0]==_T('.')&&c_file.name[1]==_T('.'))
            continue;
        TCHAR *fullPath =new TCHAR[MAX_PATH];
        _tcscpy(fullPath,path);
        _tcscat(fullPath,_T("//"));
        _tcscat(fullPath,c_file.name);
        if(c_file.attrib&_A_SUBDIR)
        {
            GetAllFileInfo(fullPath,filesPathVector);
        }
        else
        {
            //store full file path in vector.
            filesPathVector.push_back(fullPath);
            //print file info
            _tprintf(_T("FileName: %s/r/n"), fullPath);
            _tprintf(_T("ReadOnly: %s/r/n"),
                ( c_file.attrib & _A_RDONLY ) ? _T(" Y ") : _T(" N ") );
            _tprintf(_T("Hidden:   %s/r/n"),
                ( c_file.attrib & _A_HIDDEN ) ? _T(" Y ") : _T(" N ") );
            _tprintf(_T("System:   %s/r/n"),
                ( c_file.attrib & _A_SYSTEM ) ? _T(" Y ") : _T(" N ") );
            _tprintf(_T("Arch:     %s/r/n"),
                ( c_file.attrib & _A_ARCH )   ? _T(" Y ") : _T(" N ") );
            TCHAR timeBuffer[30];
            _tctime64_s( timeBuffer, _countof(timeBuffer), &c_file.time_write );
            _tprintf(_T("WriteTime:%.24s/r/n/r/n"),timeBuffer);
        }
    }
    while( _tfindnext64( hFile, &c_file ) == 0);
    //close search handle
    _findclose(hFile);
}
 
int _tmain(int argc, _TCHAR* argv[])
{
    vector<LPCTSTR> filesPathVector;
    GetAllFileInfo(_T("d://FolderForTest"),filesPathVector);
    return 0;
}

 

    打印的结果:

FileName: d:/FolderForTest/a.txt
ReadOnly:  N
Hidden:    N
System:    N
Arch:      Y
WriteTime:Sun Jun 06 12:21:22 2010

FileName: d:/FolderForTest/sub1/b
ReadOnly:  N
Hidden:    N
System:    N
Arch:      Y
WriteTime:Mon Jun 07 16:33:45 2010

 

 

paragraph SHGetFileInfo方法

    _tfinddata64_t结构体存储的信息很少,我们可能希望得到更多的文件信息,比如文件的类型,文件的图标等等,这就需要用到SHGetFileInfo函数:

DWORD_PTR SHGetFileInfo(
  __in   LPCTSTR pszPath,
  __in   DWORD dwFileAttributes,
  __out  SHFILEINFO *psfi,
  __in   UINT cbFileInfo,
  __in   UINT uFlags
);

    这是一个Windows Shell函数,需要的头文件及库为:

HeaderShellapi.h
LibraryShell32.lib
DLLShell32.dll

    pszPath指定文件的路径,uFlags指定希望获取的文件信息,而获取的文件的信息通过结构体SHFILEINFO *psfi返回。我们把这段代码加在之前的代码中,示例如下:

void GetRichFileInfo(LPCTSTR path)
{
    SHFILEINFO shfi;
    //get file name, type name and attributes. if need more, should conbined more flag by '|'
    SHGetFileInfo(path,0,&shfi,sizeof(shfi),SHGFI_TYPENAME|SHGFI_DISPLAYNAME|SHGFI_ATTRIBUTES);
    _tprintf(_T("DisplayName: %s/r/n"),shfi.szDisplayName);
    _tprintf(_T("TypeName   : %s/r/n/r/n"),shfi.szTypeName);
}
 
int _tmain(int argc, _TCHAR* argv[])
{
    vector<LPCTSTR> filesPathVector;
    GetAllFileInfo(_T("d://FolderForTest"),filesPathVector);   
    for(int i=0;i<filesPathVector.size();i++)
    {
        LPCTSTR path=filesPathVector.at(i);
        GetRichFileInfo(path);
    }
        return 0;
}
  

运行结果

DisplayName: a.txt
TypeName   : Text Document

DisplayName: b
TypeName   : File

paragraph 参考:

http://msdn.microsoft.com/en-us/library/bb762179(VS.85).aspx

http://msdn.microsoft.com/en-us/library/zyzxfzac(VS.71).aspx

http://msdn.microsoft.com/en-us/library/kda16keh(VS.80).aspx

http://msdn.microsoft.com/en-us/library/6tkkkc1y(VS.80).aspx

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值