VC++实现获取文件占用空间大小的两种方法(非文件大小)

写一个工具正好需要用到获取文件在磁盘上占用空间的大小,先普及一下知识吧
首先说一下“文件大小”和“占用空间”的区别,文件大小是指文件自身的大小,不管这个文件放在哪里大小都不会发生改变,而占用空间是指文件所在分区占用的空间,文件放在不同的分区所占用的空间可能会有所不同,占用空间一般大于等于文件大小。这里我们先做个实验,
在cmd里输入如下代码

fsutil file createnew F:\TestFile.dat 12345678
此时在F盘下创建了一个TestFile.dat的文件,然后把该文件复制到另外一个盘,文件大小和占用空间如图所示:


可以看出。两个一样的文件,在不同分区下。出现了占用空间大小不相同,这涉及到了磁盘文件的存储机制,下面解释下原因。

磁盘文件大小以字节(Byte)为单位,在文件不发生改变的情况下,大小不变,而文件在磁盘上占用的空间,是以簇(Cluster)为单位,2^n个扇区组成一个簇,一个簇只能放一个文件,所以文件的占用空间需要对齐到簇大小的整数倍,如果文件大小刚好是簇的倍数。那么文件大小和占用空间是一致的,磁盘分区格式和容量大小决定了簇的大小。所以可能出现文件在不同分区的占用空间大小不一样。在cmd下可以利用chkdsk命令来查看一个分区的簇大小,例如我这里查看F盘的结果:


这里所看到的分配单元就是簇大小,4096byte。
要计算某个文件占用空间的大小,可以使用如下的公式
簇数 = 向上取整(文件大小/簇大小)
占用空间 = 簇数 * 簇大小

获取簇的大小可以使用GetDiskFreeSpace这个API来获取每簇的扇区数和每扇区的字节数。然后相乘即可得到簇大小。
详细代码如下:

// GetFileSpaceSize.cpp : Defines the entry point for the console application.
//
/************************************************************************
 * author: HwangBae
 * created:	2012/07/21
 * Blog: http://hwangbae.cnblogs.com/
 * Email: hwangbae@live.cn
 ************************************************************************/

#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#include <math.h>


int _tmain(int argc, _TCHAR* argv[])
{
	if (argc < 2)
	{
		_tprintf_s(_T("Usage: GetFileSpaceSize filename\n"));
		return -1;
	}

	// 文件路径
	LPCTSTR szFileName = argv[1];

	// 打开文件句柄
	HANDLE hFile = ::CreateFile(szFileName, GENERIC_READ | FILE_SHARE_READ, 0, 
		NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
	if (hFile == INVALID_HANDLE_VALUE)
	{
		_tprintf_s(_T("Failed to create file handle: %s ! error code:%d\n"), szFileName, GetLastError());
		return -1;
	}

	// 获取文件大小
	UINT64 uFileSize = 0;
	::GetFileSizeEx(hFile, reinterpret_cast<PLARGE_INTEGER>(&uFileSize));
	::CloseHandle(hFile);

	// 获取磁盘根路径
	TCHAR szVolumePathName[] = _T("C:\\");
	::GetVolumePathName(szFileName, szVolumePathName, sizeof(szVolumePathName) / sizeof(TCHAR));

	// 保存簇信息的变量
	DWORD dwSectorsPerCluster = 0;
	DWORD dwBytesPerSector = 0;
	DWORD dwNumberOfFreeClusters = 0;
	DWORD dwTotalNumberOfClusters = 0;

	// 获取簇信息
	if (!::GetDiskFreeSpace(
		szVolumePathName,			//磁盘根路径
		&dwSectorsPerCluster,		//每簇的扇区数
		&dwBytesPerSector,			//每扇区的字节数
		&dwNumberOfFreeClusters,	//空余簇的数量
		&dwTotalNumberOfClusters	//全部簇的数量
		)
		)
	{
		_tprintf_s(_T("Failed to get disk cluster info! error code: %d\n"), GetLastError());
		return -1;
	}
	// 簇大小 = 每簇的扇区数 * 每扇区的字节数
	DWORD dwClusterSize = dwSectorsPerCluster * dwBytesPerSector;

	// 计算文件占用空间
	// 公式:(以字节为单位)
	// 簇数 = 向上取整(文件大小 / 簇大小)
	// 占用空间 = 簇数 * 簇大小
	UINT64 dwFileSpacesize = static_cast<UINT64>(ceil(uFileSize / static_cast<double>(dwClusterSize)) * dwClusterSize);

	_tprintf_s(_T("FileName : %s\n"), szFileName);
	_tprintf_s(_T("FileSize : %I64u Byte\n"), uFileSize);
	_tprintf_s(_T("FileSpacesSize : %I64u Byte\n"), dwFileSpacesize);
	return 0;
}

方法二:

// GetFileSpaceSize.cpp : Defines the entry point for the console application.
 //
 /************************************************************************
  * author: HwangBae
  * created:    2012/07/23
  * Blog: http://hwangbae.cnblogs.com/
  * Email: hwangbae@live.cn
  ************************************************************************/
 
 #include <windows.h>
 #include <tchar.h>
 #include <stdio.h>
 
 #define CLOSE_HANDLE(handle) \
 	do \
 	{ \
 		CloseHandle(handle); \
 		handle = NULL; \
 	} while (FALSE)
 
 int _tmain(int argc, _TCHAR* argv[])
 {
     if (argc < 2)
     {
         _tprintf_s(_T("Usage: GetFileSpaceSize filename\n"));
         return -1;
     }
 
     // 文件路径
     LPCTSTR szFileName = argv[1];
 
     // 打开文件句柄
     HANDLE hFile = ::CreateFile(szFileName, GENERIC_READ | FILE_SHARE_READ, 0, 
         NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
     if (hFile == INVALID_HANDLE_VALUE)
     {
         _tprintf_s(_T("Failed to create file handle: %s ! error code:%d\n"), szFileName, GetLastError());
         return -1;
     }
 
     // 获取文件大小
     UINT64 uFileSize = 0;
     ::GetFileSizeEx(hFile, reinterpret_cast<PLARGE_INTEGER>(&uFileSize));
 
     FILE_STANDARD_INFO fsi = {0};
     if (!::GetFileInformationByHandleEx(hFile, FileStandardInfo, &fsi, sizeof(FILE_STANDARD_INFO)))
     {
         _tprintf_s(_T("Failed to get file info! error code:%d\n"), GetLastError());
         CLOSE_HANDLE(hFile);
         return -1;
     }
 
     _tprintf_s(_T("FileName : %s\n"), szFileName);
     _tprintf_s(_T("FileSize : %I64u Byte\n"), uFileSize);
     _tprintf_s(_T("FileSpacesSize : %I64u Byte\n"), fsi.AllocationSize);
     CLOSE_HANDLE(hFile);
     return 0;
 }


测试结果:



欢迎转载本文章,但请标明出处,原文地址:

http://www.cnblogs.com/hwangbae/archive/2012/07/21/2602592.html

如果觉得本文对您有帮助,请支持一下,您的支持是我写作最大的动力,谢谢。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值