有没有快速的方法来获取磁盘上的文件数量?

时间:2017-02-22 23:49:21

标签: windows filesystems

我有一个扫描硬盘内容的Windows程序。我想显示一个有意义的进度条。有没有快速获取磁盘上文件总数的方法?这个数字不一定非精确 - 应该在10%左右的近似值。

1 个答案:

答案 0 :(得分:0)

这可能是NTFS卷。哈利约翰斯顿write的一种方式。也可能是另一种方式,通过迭代文件记录也足够快:

struct NTFS_RECORD_HEADER 
{
    enum {
        FILE = 'ELIF',
        INDX = 'XDNI',
        BAAD = 'DAAB',
        HOLE = 'ELOH',
        CHKD = 'DKHC'
    } Type;
    USHORT UsaOffset;
    USHORT UsaCount;
    USN Usn;
};

struct NTFS_FILE_RECORD_HEADER : public NTFS_RECORD_HEADER
{
    USHORT SequenceNumber;
    USHORT LinkCount;
    USHORT AttributesOffset;
    USHORT Flags;
    ULONG BytesInUse;
    ULONG BytesAllocated;
    ULONGLONG BaseFileRecord;
    USHORT NextAttributeNumber;

    enum{
        flgInUse = 1, flgDirectory = 2
    };
};

ULONG GetFileCount(HANDLE hVolume, PULONG FileCount)
{
    NTFS_VOLUME_DATA_BUFFER nvdb;

    ULONG cb, BytesReturned;
    if (!DeviceIoControl(hVolume, FSCTL_GET_NTFS_VOLUME_DATA, NULL, 0, &nvdb, sizeof(nvdb), &BytesReturned, NULL))
    {
        return GetLastError();
    }

    NTFS_FILE_RECORD_INPUT_BUFFER nfrib;

    cb = FIELD_OFFSET(NTFS_FILE_RECORD_OUTPUT_BUFFER, FileRecordBuffer[nvdb.BytesPerFileRecordSegment]);

    PNTFS_FILE_RECORD_OUTPUT_BUFFER pnfrob = (PNTFS_FILE_RECORD_OUTPUT_BUFFER)alloca(cb);

    union {
        PVOID FileRecordBuffer;
        NTFS_RECORD_HEADER* pnrh;
        NTFS_FILE_RECORD_HEADER* pnfrh;
    };

    FileRecordBuffer = pnfrob->FileRecordBuffer;

    // get maximum valid FileReferenceNumber
    ULONG a = 0, b = MAXLONG, N;
    do 
    {
        nfrib.FileReferenceNumber.QuadPart = N = (a + b) >> 1;

        DeviceIoControl(hVolume, FSCTL_GET_NTFS_FILE_RECORD, 
            &nfrib, sizeof nfrib, pnfrob, cb, &BytesReturned, 0) ? a = N + 1 : b = N;

    } while(a < b);

    if (!b)
    {
        return ERROR_GEN_FAILURE;
    }

    N = 0;
    nfrib.FileReferenceNumber.QuadPart = b - 1;

    // itterate [0, nfrib.FileReferenceNumber.QuadPart)
    do 
    {
        if (DeviceIoControl(hVolume, FSCTL_GET_NTFS_FILE_RECORD, 
            &nfrib, sizeof nfrib, pnfrob, cb, &BytesReturned, 0))
        {
            // are really file
            if (
                pnrh->Type == NTFS_RECORD_HEADER::FILE &&
                pnfrh->Flags & NTFS_FILE_RECORD_HEADER::flgInUse &&
                !pnfrh->BaseFileRecord
                )
            {
                N++;
            }
        }
        else
        {
            pnfrob->FileReferenceNumber.QuadPart = nfrib.FileReferenceNumber.QuadPart;
        }

    } while (0 <= (nfrib.FileReferenceNumber.QuadPart = pnfrob->FileReferenceNumber.QuadPart - 1));

    *FileCount = N;

    return NOERROR;
}