PhysicsFS help needed to read a directories files

Started by
5 comments, last by Servant of the Lord 9 years, 9 months ago

I am not following how one can use PhysicsFS to parse a directory for it's files and other directories...

e.g.

I want to parse my games map directory or texture directory how can I do this... I don't see a function to call to read the the directory.

Thanks

Advertisement

I'm not sure how to do that in PhysFS, but if it helps at all, boost::filesystem does that fairly easily.

Here's my own convenience functions that I use:


//Elsewhere: typedef std::vector<std::string> StringList;

enum SubFoldersEnum {IncludeSubFolders, ExcludeSubFolders};

/*
	Returns a list of every file in the folder and (if desired) the files in each sub-folder.
	If 'timeThreshold' is specified, only files that have been written to *after* that threshold are returned.
	If 'fileFilterFunc' is specified, this filters out all file names (not the entire path) that don't pass the filter.
	If 'folderFilterFunc' is specified, entire subdirectories are filtered out.
	If 'pathPrefix' is specified, this determines what prefixes the returned paths.
	Suggestions for 'pathPrefix' are: Nothing ("FolderA"), "./" ("./FolderA") for relative paths, or passing in baseFolder for absolute paths.

	Example:
		"./File1.ext"
		"./File2.ext"
		"./FolderB/File3.ext"
		"./FolderB/File4.ext"
		"./FolderB/Folder2/File5.ext"
		"./File6.ext"
*/
StringList GetFilesInDirectory(const std::string &baseFolder, SubFoldersEnum subFoldersEnum, const std::string &pathPrefix, std::time_t timeThreshold)
{
	//Call the original function, but with filters that accept everything.
	return GetFilesInDirectory(baseFolder, IsAnything, IsAnything, subFoldersEnum, pathPrefix, timeThreshold);
}

StringList GetFilesInDirectory(const std::string &baseFolder, StringValidatorFunc fileFilterFunc, SubFoldersEnum subFoldersEnum, const std::string &pathPrefix, std::time_t timeThreshold)
{
	//Call the original function, but with a directory filter that accepts everything.
	return GetFilesInDirectory(baseFolder, fileFilterFunc, IsAnything, subFoldersEnum, pathPrefix, timeThreshold);
}

StringList GetFilesInDirectory(const std::string &baseFolder, StringValidatorFunc fileFilterFunc, StringValidatorFunc folderFilterFunc,
							   SubFoldersEnum subFoldersEnum, const std::string &pathPrefix, std::time_t timeThreshold)
{
	StringList listOfFiles;
	if(!DirectoryExists(baseFolder))
		return listOfFiles;

	boost::filesystem::directory_iterator directoryIterator(baseFolder);
	boost::filesystem::directory_iterator endOfDirectory; //An unitialized iterator is the end iterator.

	//Loop through everything in this directory.
	for(; directoryIterator != endOfDirectory; directoryIterator++)
	{
		//Make sure the item found is a file and not a folder.
		if(boost::filesystem::is_regular_file(directoryIterator->path()))
		{
			//Get the name of the folder.
			std::string filename = GetFilenameFromPath(directoryIterator->path().generic_string());

			//Check if the filename passes the filter.
			if(fileFilterFunc(filename))
			{
				//Check if it was written to after 'timeThreshold'.
				if(timeThreshold == 0 || timeThreshold < boost::filesystem::last_write_time(directoryIterator->path()))
				{
					//Add it to our list.
					listOfFiles.push_back(ConvertWinPathToUnix(pathPrefix + '/' + filename));
				}
			}
		}
		else if(boost::filesystem::is_directory(directoryIterator->path()))
		{
			//Check to make sure we want to crawl subfolders.
			if(subFoldersEnum == IncludeSubFolders)
			{
				//Get the name of the folder.
				std::string directoryName = GetFinalDirectoryFromPath(directoryIterator->path().generic_string());

				//Check if the directory name passes the filter.
				if(folderFilterFunc(directoryName))
				{
					//Get all subfolders and add them to the list.
					listOfFiles += GetFilesInDirectory(baseFolder + "/" + directoryName, fileFilterFunc, folderFilterFunc, IncludeSubFolders, (pathPrefix + '/' + directoryName + '/'), timeThreshold);
				}
			}
		}
	}

	return listOfFiles;
}

'StringValidatorFunc' is a function pointer (actually, a std::function<bool(const std::string&)>) that can take a string a return either true or false if it accepts the string. I use this for filtering files. Often I pass it my SV_WildcardMatch() functor, to easily filter out something like {"*.jpg", "*.jpeg", "*.png"} - I can also post the code for that, if you desire. It's a slightly modified version of this algorithm.

I have a similar function called GetFoldersInDirectory(). It returns folder names instead of file names.

There is a function that returns a list you have to free later:

https://icculus.org/physfs/docs/html/physfs_8h.html#a0f4ae950c2dae0735a91263ddd20fbf4

There is also a callback version just below that you provide your own data and function to.

There is a function that returns a list you have to free later:

https://icculus.org/physfs/docs/html/physfs_8h.html#a0f4ae950c2dae0735a91263ddd20fbf4

There is also a callback version just below that you provide your own data and function to.

I am not following this directory path requirements... I put this in and get nothing

 
char* path = "C:/Programming/Work/SDL/Debug/";
cmd_enumerate(path);
 

static int cmd_enumerate(char *args)
{
char **rc;
 
if (*args == '\"')
{
args++;
args[strlen(args) - 1] = '\0';
} /* if */
 
rc = PHYSFS_enumerateFiles(args);
 
if (rc == NULL)
printf("Failure. reason: %s.\n", PHYSFS_getLastError());
else
{
int file_count;
char **i;
for (i = rc, file_count = 0; *i != NULL; i++, file_count++)
printf("%s\n", *i);
 
printf("\n total (%d) files.\n", file_count);
PHYSFS_freeList(rc);
} /* else */
 
return(1);
} /* cmd_enumerate */

PhysFS is virtual filesystem inspired by id tech ones, so first you mount the directories you want and then you have one, own filesystem that can look at few places or archives as if they are one.

The mounting, search path, write path and platform independent and dependent paths are all explained well on main page:

https://icculus.org/physfs/docs/html/index.html

I'm not sure how to do that in PhysFS, but if it helps at all, boost::filesystem does that fairly easily.

Here's my own convenience functions that I use:


//Elsewhere: typedef std::vector<std::string> StringList;

enum SubFoldersEnum {IncludeSubFolders, ExcludeSubFolders};

/*
	Returns a list of every file in the folder and (if desired) the files in each sub-folder.
	If 'timeThreshold' is specified, only files that have been written to *after* that threshold are returned.
	If 'fileFilterFunc' is specified, this filters out all file names (not the entire path) that don't pass the filter.
	If 'folderFilterFunc' is specified, entire subdirectories are filtered out.
	If 'pathPrefix' is specified, this determines what prefixes the returned paths.
	Suggestions for 'pathPrefix' are: Nothing ("FolderA"), "./" ("./FolderA") for relative paths, or passing in baseFolder for absolute paths.

	Example:
		"./File1.ext"
		"./File2.ext"
		"./FolderB/File3.ext"
		"./FolderB/File4.ext"
		"./FolderB/Folder2/File5.ext"
		"./File6.ext"
*/
StringList GetFilesInDirectory(const std::string &baseFolder, SubFoldersEnum subFoldersEnum, const std::string &pathPrefix, std::time_t timeThreshold)
{
	//Call the original function, but with filters that accept everything.
	return GetFilesInDirectory(baseFolder, IsAnything, IsAnything, subFoldersEnum, pathPrefix, timeThreshold);
}

StringList GetFilesInDirectory(const std::string &baseFolder, StringValidatorFunc fileFilterFunc, SubFoldersEnum subFoldersEnum, const std::string &pathPrefix, std::time_t timeThreshold)
{
	//Call the original function, but with a directory filter that accepts everything.
	return GetFilesInDirectory(baseFolder, fileFilterFunc, IsAnything, subFoldersEnum, pathPrefix, timeThreshold);
}

StringList GetFilesInDirectory(const std::string &baseFolder, StringValidatorFunc fileFilterFunc, StringValidatorFunc folderFilterFunc,
							   SubFoldersEnum subFoldersEnum, const std::string &pathPrefix, std::time_t timeThreshold)
{
	StringList listOfFiles;
	if(!DirectoryExists(baseFolder))
		return listOfFiles;

	boost::filesystem::directory_iterator directoryIterator(baseFolder);
	boost::filesystem::directory_iterator endOfDirectory; //An unitialized iterator is the end iterator.

	//Loop through everything in this directory.
	for(; directoryIterator != endOfDirectory; directoryIterator++)
	{
		//Make sure the item found is a file and not a folder.
		if(boost::filesystem::is_regular_file(directoryIterator->path()))
		{
			//Get the name of the folder.
			std::string filename = GetFilenameFromPath(directoryIterator->path().generic_string());

			//Check if the filename passes the filter.
			if(fileFilterFunc(filename))
			{
				//Check if it was written to after 'timeThreshold'.
				if(timeThreshold == 0 || timeThreshold < boost::filesystem::last_write_time(directoryIterator->path()))
				{
					//Add it to our list.
					listOfFiles.push_back(ConvertWinPathToUnix(pathPrefix + '/' + filename));
				}
			}
		}
		else if(boost::filesystem::is_directory(directoryIterator->path()))
		{
			//Check to make sure we want to crawl subfolders.
			if(subFoldersEnum == IncludeSubFolders)
			{
				//Get the name of the folder.
				std::string directoryName = GetFinalDirectoryFromPath(directoryIterator->path().generic_string());

				//Check if the directory name passes the filter.
				if(folderFilterFunc(directoryName))
				{
					//Get all subfolders and add them to the list.
					listOfFiles += GetFilesInDirectory(baseFolder + "/" + directoryName, fileFilterFunc, folderFilterFunc, IncludeSubFolders, (pathPrefix + '/' + directoryName + '/'), timeThreshold);
				}
			}
		}
	}

	return listOfFiles;
}

'StringValidatorFunc' is a function pointer (actually, a std::function<bool(const std::string&)>) that can take a string a return either true or false if it accepts the string. I use this for filtering files. Often I pass it my SV_WildcardMatch() functor, to easily filter out something like {"*.jpg", "*.jpeg", "*.png"} - I can also post the code for that, if you desire. It's a slightly modified version of this algorithm.

I have a similar function called GetFoldersInDirectory(). It returns folder names instead of file names.

yes please post it completely, I have a feeling I am going to need it and have to use boost. I didn't want to but SDL doesn't have anything to read a directories contents...

thanks!!!

Here's the convenience functions I wrapped around boost.filesystem (sometimes just a renaming of the function wink.png):

FileManagement.cpp | FileManagement.h

boost.filesystem has a boost::filepath and boost::directory class that it'd be better to use, but just incase you're interested, here's my hand-rolled functions for std::string.

PathFormatting.cpp | PathFormatting.h

CharValidators.cpp | CharValidators.h

StringValidators.cpp | StringValidators.h

WildcardMatch.cpp | WildcardMatch.h

Glancing over these files, there are a few areas where they include another header from my codebase, so you'll get some compile errors - but it should be very easy to work around that - they aren't at all badly integrated.

This topic is closed to new replies.

Advertisement