在Windows中查找超过4gb的正确文件大小

时间:2013-03-04 19:04:25

标签: c++ windows visual-studio winapi

我使用这个c ++代码在windows中查找某些文件的文件大小(使用visual studio):

(p_findFileData->nFileSizeHigh * MAXDWORD) + p_findFileData->nFileSizeLow);

如果文件大于4gb,这并没有给我正确的文件大小。经过一些研究,我试过了:

(p_findFileData->nFileSizeHigh * (MAXDWORD+1)) + p_findFileData->nFileSizeLow); 

当我读到nfilesizehigh和nfilesizelow是文件大小的64位值的32位时,如果filesize值大于32位,我们将maxdword(在我的情况下是0xffffffff)乘以nfilesizehigh。第二个解决方案也没有用,给我的尺寸比它的尺寸小。我再次尝试过这个:

ULONGLONG FileSize = (FindFileData.nFileSizeHigh * 4294967296) + FindFileData.nFileSizeLow;

它有效。此外,我还使用了另一种解决方案来获取文件大小:

 ULONGLONG FileSize = FindFileData.nFileSizeHigh;
 FileSize <<= sizeof( FindFileData.nFileSizeHigh ) *8; 
 FileSize |= FindFileData.nFileSizeLow;

上述解决方案也有效:

我想知道为什么前两个解决方案不起作用,并且如果可能的话也解释最后一个解决方案,因为我想知道代码的内部工作。非常感谢帮助。

4 个答案:

答案 0 :(得分:8)

我会用:

ULONGLONG FileSize = (static_cast<ULONGLONG>(FindFileData.nFileSizeHigh) <<
                      sizeof(FindFileData.nFileSizeLow) *8) |
                     FindFileData.nFileSizeLow;

在进入FileSize变量之前,必须先将32位值转换为64位值,然后转换为ULONGLONG。

你当然也可以使用乘法 - 但它不是以任何特定方式“更好”,并且很可能稍微慢一点[在这种特殊情况下可能没什么大不了的,但是使用乘法没有任何好处我可以看到。

现在对于“不工作”的变种:

即使这可行:

 (p_findFileData->nFileSizeHigh * MAXDWORD) + p_findFileData->nFileSizeLow);

你得到了错误的值,因为MAXDWORD小于4GB,所以你最终得到了错误的值[是的,它可能很接近,但它至少会丢错1个字节,可能更多]。但是,由于我们处理32位值,它实际上变为:

 -p_findFileData->nFileSizeHigh + p_findFileData->nFileSizeLow;

因为MAXDWORD与-1相同(是的,它可能是无符号值,但如果使值以这种方式溢出,则其行为与负有符号值相同)。

这个在数学上是正确的,但由于它溢出32位值这一事实不起作用。

 (p_findFileData->nFileSizeHigh * (MAXDWORD+1)) + p_findFileData->nFileSizeLow);

所以你得到的low part + (0 * high part)当然是不正确的。

使用强制转换,这将起作用:

 static_cast<ULONGLONG>(p_findFileData->nFileSizeHigh) * (MAXDWORD+1) +
 p_findFileData->nFileSizeLow;

答案 1 :(得分:7)

使用ULARGE_INTEGER结构组合值,而不是尝试手动计算/移位它们:

ULARGE_INTEGER ul;
ul.HighPart = p_findFileData->nFileSizeHigh;
ul.LowPart = p_findFileData->nFileSizeLow;
ULONGLONG FileSize = ul.QuadPart;

答案 2 :(得分:3)

(p_findFileData->nFileSizeHigh * MAXDWORD) + p_findFileData->nFileSizeLow);

这不能给出正确的结果,因为MAXDWORD是错误的值。

(p_findFileData->nFileSizeHigh * (MAXDWORD+1)) + p_findFileData->nFileSizeLow); 

这不起作用,因为在将类型转换为足以保存值的大小之前,您要向MAXDWORD添加+1。

(FindFileData.nFileSizeHigh * 4294967296) + FindFileData.nFileSizeLow;

这是有效的,因为4294967296是64位类型。

FileSize <<= sizeof( FindFileData.nFileSizeHigh ) *8; 
FileSize |= FindFileData.nFileSizeLow;

这是有效的,因为您将高位移位32(与乘以4294967296相同),然后使用按位或“添加”低位。

答案 3 :(得分:1)

我遇到了完全相同的问题,对于我的代码来说答案很简单。只需将MAXD​​WORD转换为64位int(例如uint64_t)。可以在我收到的here答案中找到其背后的解释。