Windows平台有一个WIN32_FIND_DATA结构,用来存储文件的一些属性(这里指的属性和下面结构中文件属性成员不同。这里的属性是指下面结构的所有成员)。
该结构的定义如下。
typedef struct _WIN32_FIND_DATA {
DWORD dwFileAttributes; //文件属性
FILETIME ftCreationTime; // 文件创建时间
FILETIME ftLastAccessTime; // 文件最后一次访问时间
FILETIME ftLastWriteTime; // 文件最后一次修改时间
DWORD nFileSizeHigh; // 文件长度高32位
DWORD nFileSizeLow; // 文件长度低32位
DWORD dwReserved0; // 系统保留
DWORD dwReserved1; // 系统保留
TCHAR cFileName[ MAX_PATH ]; // 长文件名
TCHAR cAlternateFileName[ 14 ]; // 8.3格式文件名
} WIN32_FIND_DATA, *PWIN32_FIND_DATA;
可以使用FindFirstFile()和 FindNextFile()函数可以得到 某个文件夹里面所有的文件(包括子文件夹)的WIN32_FIND_DATA结构信息。
FindFirstFile的原型如下:
HANDLE FindFirstFile(
LPCTSTR lpFileName,
LPWIN32_FIND_DATA lpFindFileData
);
FindFirstFile()函数中,第一个参数是一个字符串。可以是一个路径名或者文件名,并且支持通配符 * 和 ?。比如想查找D盘下的所有文件,可以写成D:\\*.* 或者 D:\\*。
如果只想查找D盘下的txt文件,那么可以写成D:\\*.txt。
第二个参数是指向WIN32_FIND_DATA结构体的一个指针。正如函数的名字FindFirstFile那样, 该函数会查找第一个符合查找条件的文件(使用通配符可以有多少文件满足查找条件)。然后把这个文件的一些信息写入这个结构里面。如果第一个参数没有使用通配符,而是一个文件名,那么将只能找到一个符合条件的文件。
函数的返回值是一个句柄HANDLE,说白了也就是一个整型。这个返回值可以用来查找下一个符合查找条件的文件。这就是下面的FindNextFile函数了。如果函数调用失败,将返回INVALID_HANDLE_VALUE
FindNextFile的原型如下
BOOL FindNextFile(
HANDLE hFindFile,
LPWIN32_FIND_DATA lpFindFileData
);
第一个参数就是FindFirstFile函数的返回值。第二个参数和FindFirstFile一样,在一个指针,用来存放被查找到的文件的一些信息。
如果查找成功,函数返回非0值。否则返回0。可以调用GetLastError()函数来查看失败原因。如果没有符合要求的文件了,那么也将返回0。此时,调用GetLastError()函数将返回ERROR_NO_MORE_FILES。
在使用完上面两个函数后,要记得使用CloseFile(HANDLEhFindFile)函数来关闭这个句柄。
上面三个函数需要包括windows.h头文件.
说了这么多,下面给出一个例子代码。
#include
#include
using namespace std;
int main()
{
WIN32_FIND_DATA fileAttr;
HANDLE handle;
handle = FindFirstFile("D:\\*", &fileAttr);
if( handle == INVALID_HANDLE_VALUE )
{
cout<<"invalid handle value "<
上面的程序会遍历D盘下面的所有文件和文件夹。包括当前目录和父目录,这两个目录对应的文件名为.和..,即一个点和两个点。熟悉Linux的读者就很容易明白。
也可以查找相对路径的文件,比如"*.txt",就查找当前目录下的所有txt文件
如果在编译的时候出现了cannot convert 'const char*' to 'LPCWSTR' 错误,可以把WIN32_FIND_DATA换成WIN32_FIND_DATAA,即在最后追加一个A,FindFirstFile和FindNextFile也要追加一个A。
现在看一下WIN32_FIND_DATA结构的一些成员信息。
首先看一下文件的大小信息。该信息用了两个成员存储。分别是:
DWORD nFileSizeHigh;// 文件长度高32位
DWORD nFileSizeLow;// 文件长度低32位
其中,单位是 字节数。
由于nFileSizeHigh存储的是文件长度的高位,所以当文件的大小小于MAXDWORD时,该成员的值为0。最后,可以用 (nFileSizeHigh * (MAXDWORD+1)) + nFileSizeLow 来计算文件大小。
文件夹的大小是 0。
文件类型属性由dwFileAttributes成员指明。最常用的类型当然就是:普通文件和文件夹,分别对应FILE_ATTRIBUTE_ARCHIVE和FILE_ATTRIBUTE_DIRECTORY。更多的属性可以参照这里。因为一个文件可能包含多个属性,所以判断的时候使用诸如:FILE_ATTRIBUTE_ARCHIVE & dwFileAttributes。而不是使用==符号。
现在看一下与文件有关的时间属性。有三个时间,创建时间、访问时间、修改时间。三者都差不多。只需弄懂一个,其他两个就自然知道怎么用了。
从文章最前面的WIN32_FIND_DATA结构体可以看到其ftCreationTime 成员是一个FILETIME类型。声明如下:
typedef struct _FILETIME {
DWORD dwLowDateTime;
DWORD dwHighDateTime;
} FILETIME, *PFILETIME;
一眼看过去,都不知道怎么使用。就像C语言标准库里面的time()函数一样,返回一个从1970年到现在的秒数。这个值很难使用。还好Windows还提供了另外一个结构 SYSTEMTIME。其声明如下:
typedef struct _SYSTEMTIME {
WORD wYear;
WORD wMonth;
WORD wDayOfWeek;
WORD wDay;
WORD wHour;
WORD wMinute;
WORD wSecond;
WORD wMilliseconds;
} SYSTEMTIME, *PSYSTEMTIME;
这个结构看起来才像人使用的,刚才那个完全是机器使用的。
同样,Windows提供了两者相互转换的函数.
BOOL FileTimeToSystemTime(
const FILETIME *lpFileTime,
LPSYSTEMTIME lpSystemTime
);
BOOL SystemTimeToFileTime(
const SYSTEMTIME *lpSystemTime,
LPFILETIME lpFileTime
);
两个函数都需要对应结构体的指针。
还有一个东西需要注意。
通过FindFirstFile、FindNextFile获取的WIN32_FIND_DATA结构。其FILETIME成员的值都是使用UTC时间,就是中学地理学的格林尼治时间。我们中国用东8区时间。所以我们还要在这些成员值的基础上加上 8 小时。微软不推荐我们直接对FILETIME结构进行 加上 或者减少 某个时间。如果我们要转换成我们当地的时间(就是从UTC时间转换成东8区时间),可以使用函数 FileTimeToLocalFileTime。其声明如下:BOOL FileTimeToLocalFileTime(
const FILETIME *lpFileTime,
LPFILETIME lpLocalFileTime
);
另外,不能就地修改。就是说,第一个参数和第二个参数要指向不同的内存。
给一个例子吧。
#include
#include
using namespace std;
ostream& operator << (ostream& os, const SYSTEMTIME& t)
{
os<