Windows平台C语言获取文件的一些属性

         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<iostream>
#include<windows.h>
using namespace std;

int main()
{
	WIN32_FIND_DATA  fileAttr;
	HANDLE  handle;
	handle = FindFirstFile("D:\\*", &fileAttr);

	if( handle == INVALID_HANDLE_VALUE ) 
	{
		cout<<"invalid handle value "<<GetLastError()<<endl;
	}
	else
	{
		cout<<fileAttr.cFileName<<endl; //输出查找到的文件名

		while(  FindNextFile(handle, &fileAttr)  )
		{
			cout<<fileAttr.cFileName<<endl; //输出每一个查找到的文件名
		}

		if( GetLastError() == ERROR_NO_MORE_FILES )
		{
			cout<<"查找完毕"<<endl;
		}
		else 
		{
			cout<<"查找过程出现错误"<<endl;
		}

		FindClose(handle);
	}

	return 0;
}

        上面的程序会遍历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<iostream>
#include<windows.h>
using namespace std;

ostream& operator << (ostream& os, const SYSTEMTIME& t)
{
	os<<t.wYear<<"-"<<t.wMonth<<"-"<<t.wDay<<"  ";
	os<<t.wHour<<": "<<t.wMinute<<": "<<t.wSecond<<endl;
	return os;
}

int main()
{
	
	WIN32_FIND_DATA fileAttr;
	HANDLE handle;
	
	SYSTEMTIME sysTime;
	FILETIME localFileTime;
	
	handle = FindFirstFile("D:\\*.txt", &fileAttr);
	
	if( handle == INVALID_HANDLE_VALUE )
	{
		cout<<"invalid handle value "<<GetLastError()<<endl;
	}
	else
	{
		cout<<fileAttr.cFileName<<" size is "<<((fileAttr.nFileSizeHigh * (MAXDWORD+1))  +  fileAttr.nFileSizeLow) <<endl;
		FileTimeToLocalFileTime(&fileAttr.ftCreationTime, &localFileTime); //转换成当地时间
		
		FileTimeToSystemTime(&localFileTime, &sysTime); //转换成人看的时间类型
		cout<<sysTime<<endl;
		
		FindClose(handle);
	}
	
	return 0;
}









评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值