-3

I'm using FindNextFileW to successfully list the files in a directory. The problem is that it references itself, current directory, with . and parent directory with ... I'm trying to skip these using an if condition but it still prints them.

Code:

int wmain() {

WIN32_FIND_DATAW data;
std::wstring dir = L"c:\\* ";
HANDLE hFind = FindFirstFileW(dir.c_str(), &data);

if (hFind != INVALID_HANDLE_VALUE) {
    do {
        wchar_t dot[] = L"." ;
        wchar_t dotd[] = L"..";

        if ( data.cFileName != dot && data.cFileName != dotd)
        std::wcout << data.cFileName << std::endl;
    } while (FindNextFileW(hFind, &data));
    FindClose(hFind);
}
return 0;
}

As you can see, I'm trying to skip the printing of . and .. by using an if condition. However, it still prints them. What am I doing wrong and how do I fix it?

EDIT:

This question is not about how wchar_t arrays cannot be compared. That is good to know but ultimately my question is about how to skip the . and .. in FindNextFileW. I have tried converting to std::wstring but then I can define:

std::wstring dot = '.';
std:wstring dotd = '..';

But how do I check them against cFilename?

learnerX
  • 1,022
  • 1
  • 18
  • 44
  • Arrays of any type are not comparable with the built-in operators. –  Jun 13 '19 at 22:25
  • `SIZE_T FileNameLength = wcslen(data.cFileName); switch (FileNameLength) { case 2: if (data.cFileName[1] != '.') break; case 1: if (data.cFileName[0] == '.') continue; }` – RbMm Jun 13 '19 at 22:27
  • _"This question is not about how wchar_t arrays cannot be compared"_ That's exactly what it's about. What the `wchar_t` arrays contain is irrelevant, and therefore `FindNextFileW` (and the Windows API in general) are also irrelevant. Divide and conquer. Reduce your problem. – Lightness Races in Orbit Jun 13 '19 at 22:38
  • It's a duplicate many times over. You skip these items by performing string comparison. – David Heffernan Jun 13 '19 at 22:39

2 Answers2

6

You are just comparing the pointers and they will never be the same. data.cFileName is not a std::[w]string, it is just a plain C-style string.

You could use lstrcmpW(), but these are so short you don't even have to do that, just check the characters manually or use a helper function:

template<class T> bool IsDotOrDotDot(const T*s)
{
  if (s[0] == T('.'))
  {
    if (s[1] == T('\0')) return true; // .
    if (s[1] == T('.') && s[2] == T('\0')) return true; // ..
  }
  return false;
}

...

do {
  if (!IsDotOrDotDot(data.cFileName))
  {
    ...
  }
} while (...);
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
Anders
  • 97,548
  • 12
  • 110
  • 164
4

You can just do:

if (wcscmp (data.cFileName, dot) != 0 && wcscmp (data.cFileName, dotd) != 0)
    ...

Note also that:

wchar_t dot[] = L"." ;

should be:

const wchar_t dot[] = L"." ;

and likewise for dotd.

If using C++17, you might also like to look into std::filesystem

Paul Sanders
  • 24,133
  • 4
  • 26
  • 48
  • 1
    really here can be more efficient code, compare strcmp, but of course this is also ok – RbMm Jun 13 '19 at 22:29
  • 1
    Why even `[]` not `*`; no need for a copy – Lightness Races in Orbit Jun 13 '19 at 22:51
  • In fact you _may_ want to take the shortcut that accidentally led to the "hidden files" convention on Linux (though I realise this is for Windows), and just check the first character for being `L'.'`. Depends what you need to do though. – Lightness Races in Orbit Jun 13 '19 at 22:52
  • 2
    @LightnessRacesinOrbit Windows allows directory and file names to begin with `.`, and I have seen many apps take advantage of that, like Minecraft, TortoiseSVN, etc – Remy Lebeau Jun 13 '19 at 23:23
  • @RemyLebeau The apps you list surely make use of leading `.` in the same way as they would on Linux (even though it's not a Windows convention in the truest sense; find a native tool that cares about leading `.`!) What I'm saying is that it is up to the OP as to whether they want to adopt this convention in their app or not; if they do, they can simplify this logic substantially. – Lightness Races in Orbit Jun 13 '19 at 23:44
  • @LightnessRacesinOrbit _Why even `[]` not `*`; no need for a copy_ - I didn't read it very carefully - I thought it _was_ `.`! – Paul Sanders Jun 13 '19 at 23:47
  • What I mean is that, by using `[]`, the OP is copying the string literal into a local array when they don't need to. Just `const wchar_t* dot = L".";` will do fine – Lightness Races in Orbit Jun 14 '19 at 00:05