Get list of files with *.dds

5dd66e0225657f6ea919eb133ced3e68
0
Phlex 101 May 04, 2009 at 09:37

Hey, I’ve been looking into populating an array of LPCSTR’s with the file paths of all the .dds files in a particular folder (Media/LightProbes/). I’ve seen a number of methods that use the boost libraries file system but I’d rather stay away from boost for now.
The basic process would go like this

scan the folder
int numDDSFiles = 0;
for (each file, check dds)
numDDSFiles++;

LPCSTR DirectoryArrays[numDDSFiles];
for(int i = 0; i < numDDSFiles; i++)
{
DirectoryArrays = “Media/LightProbes/” + fileName + “dds”;
}

trouble is I don’t know how to check how many files there are in a particular file that have a certain file extension, or how to get what that file name is. I’d be happy to use STL or Win32 library and am open to other methods, but as stated above would rather not use boost.

Thanks =)

24 Replies

Please log in or register to post a reply.

5dd66e0225657f6ea919eb133ced3e68
0
Phlex 101 May 05, 2009 at 04:45

hey monjardin, thanks for the reply. I’m having some trouble understanding how it works, and how to implement, I understand that under his given framework, I would add a filter for *.dds files where he says this:

You can implement simple filtering by filename (or extension) like this:

bool CheckUseFile(LPCTSTR, WIN32_FIND_DATA* pwfd)
{
return ::PathMatchSpec(pwfd->cFileName, _T(“*.jpg”));
}

although much of the code that is presented in the download file seems very complicated and I’m finding it difficult to understand, is there not an easier way to go about it?

Thanks

A8433b04cb41dd57113740b779f61acb
0
Reedbeta 167 May 05, 2009 at 05:05

Do you just want to find files in a single folder (no sub-folders), or an entire tree (folders, its sub-folders, and their sub-folders, etc…)? For an entire tree, monjardin’s link may be useful, but if you just want to look at a single folder, you can just use FindFirstFile and FindNextFile. You’d pass FindFirstFile a search string like “c:\myproject\*.dds”, then run a loop calling FindNextFile until it returns false.

5dd66e0225657f6ea919eb133ced3e68
0
Phlex 101 May 05, 2009 at 05:20

I’m just looking to find the files in a single folder, “Media/LightProbes/” and get just the names of the files with a .dds file extension.

A8433b04cb41dd57113740b779f61acb
0
Reedbeta 167 May 05, 2009 at 05:26

Then FindFirstFile and FindNextFile should be effective and pretty simple to use.

5dd66e0225657f6ea919eb133ced3e68
0
Phlex 101 May 05, 2009 at 06:10

k thanks :)

5dd66e0225657f6ea919eb133ced3e68
0
Phlex 101 May 05, 2009 at 07:35

Ok, I’ve tried implementing a simple one that just gets all the files in a directory, here’s the code

HANDLE hHandle;
    WIN32_FIND_DATA* pData = NULL;
    std::vector<LPCSTR> Directories;

    hHandle = FindFirstFile("Media/LightProbes/", pData);

    BOOL bMoreFiles = TRUE;
    while(bMoreFiles == TRUE)
    {
        bMoreFiles = FindNextFile(hHandle, pData);
        if(bMoreFiles == TRUE)
        {
            Directories.push_back(LPCSTR(pData->cFileName));
        }
    }

but when I check the size of Directories and it is 0, I have checked in the file Media/LightProbes and there are 9 files there, what’s happening?

6673a7d3bfd3d1db5e05c5676cc040b6
0
Goz 101 May 05, 2009 at 08:14

Try this …

HANDLE hHandle;
    WIN32_FIND_DATA* pData = NULL;
    std::vector<LPCSTR> Directories;

    hHandle = FindFirstFile("Media/LightProbes/*", pData);

    BOOL bMoreFiles = TRUE;
    while(bMoreFiles == TRUE)
    {
        bMoreFiles = FindNextFile(hHandle, pData);
        if(bMoreFiles == TRUE)
        {
            Directories.push_back(LPCSTR(pData->cFileName));
        }
    }

Edit: Heh … the code block appears to get proper confused by a /* in a string …

5dd66e0225657f6ea919eb133ced3e68
0
Phlex 101 May 05, 2009 at 08:55

Hey, thanks for the reply, I’m getting a compile error that directs me to this in vector

bool _Buy(size_type _Capacity)
{ // allocate array with _Capacity elements
_Myfirst = 0, _Mylast = 0, _Myend = 0;
if (_Capacity == 0)
return (false);
else if (max_size() < _Capacity)
_Xlen(); // result too long
else
{ // nonempty array, allocate storage
_Myfirst = this->_Alval.allocate(_Capacity);
_Mylast = _Myfirst;
_Myend = _Myfirst + _Capacity;
}
return (true);
}

6673a7d3bfd3d1db5e05c5676cc040b6
0
Goz 101 May 05, 2009 at 09:34

And what does the error tell you?

There is another bug though. An LPCSTR is a Long Pointer to a Constant STRing. Basically after you call FindNextFile the pData->cFileName is most probably de-allocated and freed. To fill your structure you should be copying the string to your own allocation (Which you, of course, need to free after you’ve used it).

So try this code …

HANDLE hHandle;
WIN32_FIND_DATA* pData = NULL;
std::vector<TCHAR*> Directories;

hHandle = FindFirstFile("Media/LightProbes/*", pData);

BOOL bMoreFiles = TRUE;
while(bMoreFiles == TRUE)
{
    bMoreFiles = FindNextFile(hHandle, pData);
    if(bMoreFiles == TRUE)
    {
        const size_t strLen = _tcslen( pData->cFileName ) + 1;
        TCHAR* pNewStr      = new TCHAR[strLen];
        _tcscpy_s( pNewStr, strLen, pData->cFileName );
        Directories.push_back( pNewStr );
    }
}
5dd66e0225657f6ea919eb133ced3e68
0
Phlex 101 May 05, 2009 at 09:41

Hey, what includes and lib’s do I need for _tcslen and _tcscpy_s?

6673a7d3bfd3d1db5e05c5676cc040b6
0
Goz 101 May 05, 2009 at 09:46

you need to #include <tchar.h>

6673a7d3bfd3d1db5e05c5676cc040b6
0
Goz 101 May 05, 2009 at 09:47

Its worth noting that all its doing is modifying the code so that it will work with UTF-8 or UTF-16 strings. You can easily change TCHAR to char and change _tcs* to str*

5dd66e0225657f6ea919eb133ced3e68
0
Phlex 101 May 05, 2009 at 09:49

Got the same thing as before, with that section from vector and this:

First-chance exception at 0x7c902128 in RTHDRIBLEngine.exe: 0xC0000005: Access violation writing location 0x00000000.
Unhandled exception at 0x7c902128 in RTHDRIBLEngine.exe: 0xC0000005: Access violation writing location 0x00000000.

6673a7d3bfd3d1db5e05c5676cc040b6
0
Goz 101 May 05, 2009 at 09:54

Oh yeah don’t use a WIN32_FIND_DATA pointer unless you are prepared to allocate the memory for it. Basically you are telling FindFirstFile to fill memory at address 0 (NULL) and that raises an access violation (0xc0000005) from Windows.

Read the documentation …

http://msdn.microsoft.com/en-us/library/aa364418(VS.85).aspx

6673a7d3bfd3d1db5e05c5676cc040b6
0
Goz 101 May 05, 2009 at 09:58

because i’m feeling nice (Even though the link above has a perfect explanation of how to use FindFirstFile) … this code should work. If it doesn’t i suggest you try to figure out why (because I haven’t compiled or run the code, myself) using the documentation.

HANDLE hHandle;
WIN32_FIND_DATA data;
std::vector<TCHAR*> Directories;

hHandle = FindFirstFile("Media/LightProbes/*", &data );

BOOL bMoreFiles = TRUE;
while(bMoreFiles == TRUE)
{
    const size_t strLen = _tcslen( data.cFileName ) + 1;
    TCHAR* pNewStr      = new TCHAR[strLen];
    _tcscpy_s( pNewStr, strLen, data.cFileName );
    Directories.push_back( pNewStr );

    bMoreFiles = FindNextFile( hHandle, &data );
}
Fd80f81596aa1cf809ceb1c2077e190b
0
rouncer 103 May 05, 2009 at 10:02

Why dont you learn the windows file explorer.

6673a7d3bfd3d1db5e05c5676cc040b6
0
Goz 101 May 05, 2009 at 10:06

@rouncer

Why dont you learn the windows file explorer.

How does that help you to programmatically enumerate files in a directory?

5dd66e0225657f6ea919eb133ced3e68
0
Phlex 101 May 05, 2009 at 10:22

Cool, it seems to work prefectly now, here’s the code for getting all of a certain type of file ina folder (I find all .dds files obviously, just change the file extension on the FindFirstFile function);

    HANDLE hHandle;
    WIN32_FIND_DATA pData;
    std::vector<TCHAR*> Directories;

    hHandle = FindFirstFile("Media/LightProbes/*.dds", &pData);

    const size_t strLen = _tcslen( pData.cFileName ) + 1;
    TCHAR* pNewStr      = new TCHAR[strLen];
    _tcscpy_s( pNewStr, strLen, pData.cFileName );
    Directories.push_back( pNewStr );

    BOOL bMoreFiles = TRUE;
    while(bMoreFiles == TRUE)
    {
        bMoreFiles = FindNextFile(hHandle, &pData);
        if(bMoreFiles == TRUE)
        {
            const size_t strLen = _tcslen( pData.cFileName ) + 1;
            TCHAR* pNewStr      = new TCHAR[strLen];
            _tcscpy_s( pNewStr, strLen, pData.cFileName );
            Directories.push_back( pNewStr );
        }
    }

As a note to others, make sure you save the name of whatever cFileName is after FindFirstFile is called otherwise you will miss it out as FindNextFile will not go back to the start of the file, thanks heaps Goz for your help, just another couple of questions if you don’t mind?

  1. ok, so I’ve got the name and file extension, how can I effectively go

LPCSTR caPaths[Directories.size()];

for(int i = 0; i < Directories.size(); i++)
{
caPaths = LPCSTR(“Media/LightProbes/” + Directory);
}

??

  1. What exactly is an “access violation”? I’ve seen them so many times but never actually known what they are.

Again thank you for your help.

6673a7d3bfd3d1db5e05c5676cc040b6
0
Goz 101 May 05, 2009 at 10:37

@Phlex

  1. ok, so I’ve got the name and file extension, how can I effectively go

LPCSTR caPaths[Directories.size()];

for(int i = 0; i < Directories.size(); i++)
{
caPaths = LPCSTR(“Media/LightProbes/” + Directory);
}

??

Firstly you should be using LPSTRs not LPCSTRs as the const will play havoc with you. Secondly you don’t seem to have an idea as to how pointers work. You need to allocate the space for the string before you assign to it.

Failing that you could just use the STL string (std::string).

Using that you could re-write that code as

std::string caPaths[Directories.size()];

for(int i = 0; i < Directories.size(); i++)
{
    caPaths[i] = std::string( "Media/LightProbes/" ) + std::string( Directory[i] );
}

This way you are letting C++ do all the work. Microsoft also provides a similar string class called CString. Its available under MFC and ATL. Failnig that I’m sure there are several string classes you could use. I wrote myself one recently for some cross platform fun.

  1. What exactly is an “access violation”? I’ve seen them so many times but never actually known what they are.

An access violation is an exception raised by the operating system. It informs you that you have tried to access some memory you aren’t allowed to access (hence access violation). You can easily recreate them by writing to a NULL pointer, writing to a pointer higher than 0x80000000 (in a standard win32 setup) or, simply, by writing to a block of memory that hasn’t been assigned to your process (ie allocated).

Primarily I think you need to do more research into what pointers are and how to use them as this does appear to be quite a large hole in your current knowledge.

0b249c591e8611305d28bbdf42420732
0
AdrianD 101 May 05, 2009 at 10:43

don’t forget to call FindClose(Handle) when you finshed searching.

Fd80f81596aa1cf809ceb1c2077e190b
0
rouncer 103 May 05, 2009 at 16:55

Oh i didnt understand, i thought youy were just writing a file loader, sorry my mistake.

5dd66e0225657f6ea919eb133ced3e68
0
Phlex 101 May 05, 2009 at 19:53

I quite agree, my knowledge on pointers is rather terrible, thanks for the help everyone, your comments are all taken into consideration.

@Adrian, thanks for the tip :)

@rouncer, no trouble, thanks for helping

6673a7d3bfd3d1db5e05c5676cc040b6
0
Goz 101 May 05, 2009 at 21:29

@Phlex

I quite agree, my knowledge on pointers is rather terrible, thanks for the help everyone, your comments are all taken into consideration.

I’d strongly recommend looking into a bit of assembly (Simply debugging your code using the disasembler is a great way to learn if you are prepared to figure out what is going on in memory and the registers). It will give you a great idea of how memory works.

Addressable memory on a standard win 32 process can be thought of as a HUGE array of 2\^31 bytes (or chars). A memory address is just the array index into that array. Its obviously gets a lot more complicated than that because you cannot guarantee exactly where memory will be allocated. However if you allocated a struct that has 4 DWORDs in it you know that there are 4 DWORDS each DWORD is made of 4 bytes. Therefore the allocate takes 16 bytes. The memory address of the structure is the first “index” of the first byte. So to get the 3rd DWORD in the structure you know it is the base index PLUS 12 bytes. The following 4 bytes then make up the DWORD.

Not sure that will help at all .. but well worth spending some serious time playing with pointers :)