在Windows平台上寻找大文件的C++方法

3

我正在编写一个小型实用程序来解析Windows上的xfs文件系统。 对于小于5GB的小型图像,我的实用程序可以正常工作:我能够列出所有文件和目录。 但是当我尝试解析大于30GB的xfs图像时,它会给出错误的结果。 我使用_fseeki64和_ftelli64进行搜索,并使用fread读取特定块。 我注意到其中一个问题是_fseeki64无法正常工作。 下面是我的搜索函数,它会搜索特定的组号和块号。

int FileSystemReadXFS::SeekToGroupBlock(uint16_t grpNum, uint64_t blockNum)
    {
        int error = -1;
        //Seek to beginning
        if(_fseeki64(m_fileSystemInfo.fp, (__int64)0, SEEK_SET) != 0)
        {
            PRINT_SEEK_ERROR;
            goto BAILOUT;
        }
        __int64 currPtr = 0;
        //Seek to destination group
        if(grpNum > 0)
        {
            if(_fseeki64(m_fileSystemInfo.fp, (__int64)(grpNum*m_fileSystemInfo.SizeOfBlockGroup*m_fileSystemInfo.BlockSize), SEEK_SET))
            {
                PRINT_SEEK_ERROR;
                    goto BAILOUT;
            }
             currPtr = _ftelli64(m_fileSystemInfo.fp);
        }


        //Seek to destination block in group
        if(blockNum > 0)
        {
            if(_fseeki64(m_fileSystemInfo.fp, (__int64)(blockNum*m_fileSystemInfo.BlockSize), SEEK_CUR))
            {
                PRINT_SEEK_ERROR;
                goto BAILOUT;
            }
            currPtr = _ftelli64(m_fileSystemInfo.fp);
        }
        error = 0;
BAILOUT:
        return error;
    }

然而,上述函数将我带到了错误的位置。例如,当我想要查找组号为2,并且m_fileSystemInfo.SizeOfBlockGroup = 2043982且m_fileSystemInfo.BlockSize = 4096时。
我期望的currPrt = 2043982 * 4096 * 2 = 16744300544(0x3E609C000),但_ftelli64返回的是(0xE609C000)。请建议可能出了什么问题。此外,请建议在C++中处理Windows上的大文件的最佳方法。
更新:
我发现seekOffset被限制为8154365952(0x1e609c000),而不是实际值16744300544(0x3e609c000),即使我使用__int64。
所以,
__int64 seekOff = (__int64)(grpNum * m_fileSystemInfo.SizeOfBlockGroup * m_fileSystemInfo.BlockSize) = 2 * 2043982 * 4096
给出的结果是8154365952,而不是16744300544。
我不确定原因是什么,因为所有变量都是__int64类型。
2个回答

4

显然问题出在查找偏移量的计算上。它导致了整数溢出。 因此,即使我正在处理64位应用程序,我不得不将所有内容转换为__int64。我曾想过编译器可能会为我完成这项工作。

__int64 grpNum = 2;
__int64 sizeOfBlockGroup = 2043982;
__int64 blockSize = 4096;
__int64 seekOffSet = grpNum*sizeOfBlockGroup*blockSize;

这对于_fseeki64和__ftelli64非常有效。


在64位Windows所使用的内存模型中,指针是64位的,但整数是32位的。此外,您不必将所有值都设置为__int64,只需确保如果A * B大于32位,则A或B是__int64即可。 - Stuart

2
你最好直接使用Win32 API而不是通过C运行时来实现。
使用CreateFile打开文件,使用SetFilePointerEx进行查找。
你调用的函数最终也会调用这些API。在Visual Studio中,你可以使用CRT代码进入_fseeki64并可能看到它出错的地方。

我发现220439824096的偏移计算被限制在8154365952,而不是实际值16744300544。我大多数地方都使用了__int64,但这并没有帮助。 - praks411

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接