cwindowswinapi

How can I get the file size with FindFirstFileW and FindNextFileW? (beginner)


I'm a beginner with the Windows API and C Programming, I am trying to get the file size from my files, but my output is not so as expected.

That's my code:

#include <Windows.h>
#include <wchar.h>
#include <stdio.h>

#pragma warning(disable : 4996)

#define ANSI_RESET         "\x1b[0m"
#define ANSI_GREEN         "\x1b[32m"
#define ANSI_BRIGHT_MAGENTA "\x1b[95m" 

int wmain() {
    WIN32_FIND_DATAW fd;
    wprintf(L"Pfad zum Lesen: ");
    wchar_t inputPath[MAX_PATH];
    fgetws(inputPath, MAX_PATH, stdin);

    size_t len = wcslen(inputPath);
    if (len > 0 && inputPath[len - 1] == L'\n') { 
        inputPath[--len] = L'\0';
    }
    if (len > 0 && inputPath[len - 1] == L'\r') {
        inputPath[--len] = L'\0';
    }

    if (len > 0 && inputPath[len - 1] != L'\\') {
        wcscat(inputPath, L"\\");
    }

    //wcscat fügt ein zeichen hinzu
    wcscat(inputPath, "*");
    wprintf(L"Debug: %ls\n", inputPath);

    HANDLE hFirstFile = FindFirstFileW(
        inputPath,
        &fd
    );

    if (hFirstFile == INVALID_HANDLE_VALUE) {
        wprintf(L"hFirstFile Fehlgeshlagen mit: %lu", GetLastError());
        return 1;
    }

    do {
        
        
        wprintf(L"Name: "ANSI_BRIGHT_MAGENTA"%ls\n"ANSI_RESET, fd.cFileName);
        wprintf(L"Groesse: %lu\n", fd.nFileSizeHigh);
        wprintf(L"\n");
    } while (FindNextFileW(hFirstFile, &fd));

    FindClose(hFirstFile);

    return 0;
}

and this is my output:

Name: .
Groesse: 0

Name: . .
Groesse: 0

Name: vorlage.docx
Groesse: 0

Name: Seite 3 Lernaufgabe 1.docx
Groesse: 0

Name: Seite 3 Lernaufgabe 2.docx
Groesse: 0


Solution

  • The reason why you are getting zeros for file sizes is because you are only printing the nFileSizeHigh field, which contains the high-order 32-bit component of the whole 64-bit file size:

    wprintf(L"Groesse: %lu\n", fd.nFileSizeHigh);
    

    You have to combine both the 32-bit high-order and 32-bit low-order components of the file size into a single 64-bit value.

    Combining the Two 32-bit Size Components into a Single 64-bit Size

    The Microsoft documentation for the WIN32_FIND_DATAW structure contains this description about the nFileSizeHigh field:

    nFileSizeHigh

    The high-order DWORD value of the file size, in bytes.

    This value is zero unless the file size is greater than MAXDWORD.

    The size of the file is equal to (nFileSizeHigh * (MAXDWORD+1)) + nFileSizeLow.

    So, it basically already gave you the formula for computing the total file size, expressed as a 64-bit integer, in terms of the two 32-bit "size component" fields nFileSizeLow and nFileSizeHigh.

    You can also use the ULARGE_INTEGER union, setting "as input" its HighPart and LowPart 32-bit fields, and reading back "as output" the whole 64-bit QuadPart field:

    WIN32_FIND_DATAW findData;
    // ...
    
    ULARGE_INTEGER uliFileSize;
    // Set the two 32-bit size components
    uliFileSize.HighPart  = findData.nFileSizeHigh;
    uliFileSize.LowPart   = findData.nFileSizeLow;
    
    // Read back the whole 64-bit size
    ULONGLONG ullFileSize = uliFileSize.QuadPart;
    

    Printing the 64-bit Size with wprintf/printf

    To print the file size as an unsigned 64-bit integer, you can use the format specifier %I64u, as described in the Format Specification Syntax documentation page for printf and wprintf:

    wprintf(L"File size: %I64u bytes.\n", ullFileSize);
    

    I64 is the size prefix, meaning that you are passing a 64-bit integer argument, and u is the type field specifying that this is an unsigned decimal integer.