Read all files inside a folder including files in subfolders using C++ - c++

I want to read all files inside a given folder(path to folder) using FindFirstFile method provide in windows API. Currently I'm only succeeded in reading files inside the given folder. I could not read files inside sub folders. Can anyone help me to do this??

When you call FindFirstFile/FindNextFile, some of the "files" it returns will actually be directories.
You can check if something is a directory or not by looking at the dwFileAttributes field of the WIN32_FIND_DATA structure that gets returned to you.
If you find one that is a directory, then you can simply call your file finding function recursively to go into the subfolders.
Note: Make sure to put in a special case for the . and .. psuedo-directories, otherwise your function will recurse into itself and you'll get a stack overflow
Here's the documentation if you haven't already found it:
FindFirstFile
WIN32_FIND_DATA
possible values for dwFileAttributes (remember these are all bit flags, so you'll have to use & to check)

Alternatively, you can use boost::filesystem which will not only give you a clean API, but will also make your code portable on all supported platforms.

Take a look at this example from MSDN using CFileFind.

I've used this code to read the files in the specified directory.
CFileFind finder;
BOOL bWorking = finder.FindFile( directory );
while( bWorking )
{
bWorking = finder.FindNextFile();
}//end while

Related

Finding the file path of all files in a folder

I'm trying to convert a bunch of images to textures using SDL. So far, I know its possible to do everything manually:
//Load front alpha texture
if (!gModulatedTexture.loadFromFile("14_animated_sprites_and_vsync/text2.png"))
{
printf("Failed to load front texture!\n");
success = false;
}
else
.....
However, I have quite a few images I want to load so what I'm looking for is a way to automate the process. I want to put all my images into a single folder, and then do something like this:
i=0
while (there are still images to load) {
textureBank[i] = current image
i++
}
I wast thinking there might be some easy way to just read in the file path of all the files in a directory, but I haven't been able to find a way to do that.
Any suggestions?
You don't need to use any 3rd-party library like boost, just call the following function (for Windows OS). After this, you will get all file paths within given folder in vector<string>.
#include <Windows.h>
// folder must end with "/", e.g. "D:/images/"
vector<string> get_all_files_full_path_within_folder(string folder)
{
vector<string> names;
char search_path[200];
sprintf(search_path, "%s*.*", folder.c_str());
WIN32_FIND_DATA fd;
HANDLE hFind = ::FindFirstFile(search_path, &fd);
if(hFind != INVALID_HANDLE_VALUE)
{
do
{
// read all (real) files in current folder, delete '!' read other 2 default folder . and ..
if(! (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) )
{
names.push_back(folder+fd.cFileName);
}
}while(::FindNextFile(hFind, &fd));
::FindClose(hFind);
}
return names;
}
Since you are using SDL, I’ll assume you want to be cross-platform. The boost::filesystem library can do this.
Take a look at their directory iteration example.
Although it’s part of a 3rd-party library, boost::filesystem is proposed for inclusion in a future C++ standard, TR2, so it’s worth the effort to learn. It should eventually be the standard C++ way to work with files and directories.

c++ - resolve all symbolic links defined in a file path

Short version
how do I get a resolved path from a path that one of its dirs are symbolic link:
example:
Say path = /x/y/d/f1 where y is a symbolic link to /a/b
so the result of resolved file path would be:
/x/a/b/d/f1
Long version
I'd like to write a c++ function that copy files from dir1 to dir2 (of course this is not the actual issue but a reduction of bigger and more complex problem).
Prior to the copy process I'd like to remove all files in dir2 that are going to be copied from dir1.
Say I have:
Dir1 = /a/b/c/d
Dir2 = /x/y/d/
Assume I have file 'f1' in dir1 and file 'f1' in dir2, so my process would do:
remove /x/y/d/f1
copy /a/b/c/d/f1 to /x/y/d/f1
My problem is the following:
Say dir 'y' is a symbolic link to /a/b/c/.
Now when I remove /x/y/d/f1, I am actually removing /a/b/c/d/f1.
(my example may have holes in it, but I hopw you get the idea)
I'd like to avoid this, meaning, when I come to remove /x/y/d/f1 I want to be able to know that I'll be removing /x/y/d/f1 and skip that remove
I tried using POSIX readlink() function but it only works when the file 'f1' itself is a symbolic link BUT does not work when one of its parent dirs is a symbolic link.
Any ideas?
Following link will give you the answer.
http://ubuntuforums.org/showthread.php?t=1126617
You can use following code to resolve symilnks:
char buf[512];
int count = readlink("/x/y/d", buf, sizeof(buf));
if (count >= 0) {
buf[count] = '\0';
printf("%s -> %s\n", argv[1], buf);
}
In above code "d" path component should be the symlink. So you will have to iterate and resolve each path component.
If you just want to avoid the said collision scenario, it is easier to create a canary file and try to access it through the other constructed path. If you meant the question in general, for full-dir operations.
If it's not clear: if you create /x/y/d/TEMP123456 it will appear as /a/b/c/d/TEMP123456 (or the other way around) if they actually point to same dirs.
For a single file it may be even easier: open the source file for exclusive access before trying to delete it in target dir. (I'm not sure how reliable that is if you add NFS systems to the mix.)

Getting full path of file in COCOS2D-X on Android devices

I am trying to obtain an XML file in my project but I can't seem make work right.
I am using libXML (the one that comes with cocos2d-x-2.0.4) to parse XML files.
I'm using CCFileUtils::sharedFileUtils() -> fullPathFromRelativePath( ); but the problem is, for Android versions, it will not give the full path. It works fine on iOS, though.
I then looked at the GitHub and saw something weird. It turns out that fullPathFromRelativePath( ) will only return whatever you pass onto it.
From the GitHub:
const char* CCFileUtils::fullPathFromRelativePath(const char *pszRelativePath)
{
return pszRelativePath;
}
I've looked everywhere and all I get is how to read XML files using CCFileUtils. I am already able to parse XML files. The only issue is that I can't get the full path of the XML file using fullPathFromRelativePath() in Android.
How can I get the full path of the XML file in Android?
There is nothing wrong with that function. The problem is that your xml files are inside apk, which is a zipped file, you cannot read that file directly, you should use something like
long tmpSize;
const char* xmlData = CCFileUtils::sharedFileUtils()->getFileData(YOUR_PATH_TO_FILE, "r", &tmpSize);
then you can use lib xml to handle the data you get.
but remember you cannot modify anything inside apk file. if you want to write to xml, you need to copy it to some writable path first (like sdcard or using getWritablePath()).
For the files not inside apk, you can use fopen() directly, you do not need getFileData() any more.
Hope this helps.

How to use fstream objects with relative path?

Do I always have to specify absolute path for objects instantiated from std::fstream class? In other words, is there a way to specify just relative path to them such as project path?
You can use relative paths as well. But they are relative to the environment you call your executable from.
This is OS dependent but all the major systems behave more or less the same AFAIK.
Windows example:
// File structure:
c:\folder\myprogram.exe
c:\myfile.txt
// Calling command from folder
c:\folder > myprogram.exe
In the above example you could access myfile.txt with "c:/myfile.txt" or "../myfile.txt". If myprogram.exe was called from the root c:\ only the absolute path would work, but instead "myfile.txt" would work.
As Rob Kennedy said in the comments there's really nothing special about paths regarding fstream. But here is a code example using a relative path:
#include <fstream>
int main() {
std::ifstream ifs("../myfile.txt");
... // Do something sensible with the file
}
If you have an .exe file running from C:\Users\Me
and you want to write a file to C:\Users\Me\You\text.txt,
then all what you need to do is to add the current path operator ., so:
std::ifstream ifs(".\\you\\myfile.txt");
will work
You can use relative paths. They're treated the same as relative paths for any other file operations, like fopen; there's nothing special about fstream in that regard.
Exactly how they're treated is implementation-defined; they'll usually be interpretted relative to your process's current working directory, which is not necessarily the same as the directory your program's executable file lives in. Some operating systems might also provide a single working directory shared by all threads, so you might get unexpected results if a thread changes the working directory at the same time another thread tries to use a relative path.
Say you have a src folder directly under your project directory and the src folder contains another tmp_folder folder which contains a txt file named readMe.txt. So the txt file can be read in this way
std::ifstream fin("../src/tmp_folder/readMe.txt");
The behaviour is OS specific. Therefore, the best way to handle this IMHO is to make it somebody else's problem. Read the path to the file to open as a string from the user (e.g: command line argument, config file, env variable etc..) then pass that string directly to the constructor of fstream. Document that this is how your program behaves.
I wrote more about path manipulation here: https://stackoverflow.com/a/40980510/2345997
You can specify a path relative to current directory. On Windows you may call GetCurrentDirectory to retrieve current directory or call SetCurrentDirectory to set current directory. There are also some CRT functions available.
On linux also:
// main.cpp
int main() {
ifstream myFile("../Folder/readme.txt");
// ...
}
Assuming the folder structure is something like this:
/usr/Douments/dev/MyProject/main.cpp
/usr/Documents/dev/MyProject/Folder/readme.txt
What I ended up using was a relative path as identified on How to open a file with relative path in C++? which ended up being:
myFile.open("../Release/frequency.dat", ios::in);
*changing myFile to whatever your variable is.

Efficiently List All Sub-Directories in a Directory

Please see edit with advice taken so far...
I am attempting to list all the directories(folders) in a given directory using WinAPI & C++.
Right now my algorithm is slow & inefficient:
- Use FindFirstFileEx() to open the folder I am searching
- I then look at every file in the directory(using FindNextFile()); if its a directory file then I store its absolute path in a vector, if its just a file I do nothing.
This seems extremely inefficient because I am looking at every file in the directory.
Is there a WinAPI function that I can use that will tell me all the sub-directories in a given directory?
Do you know of an algorithm I could use to efficiently locate & identify folders in a directory(folder)?
EDIT:
So after taking the advice I have searched using FindExSearchLimitToDirectories but for me it still prints out all the files(.txt, etc.) & not just folders. Am I doing something wrong?
WIN32_FIND_DATA dirData;
HANDLE dir = FindFirstFileEx( "c:/users/soribo/desktop\\*", FindExInfoStandard, &dirData,
FindExSearchLimitToDirectories, NULL, 0 );
while ( FindNextFile( dir, &dirData ) != 0 )
{
printf( "FileName: %s\n", dirData.cFileName );
}
In order to see a performance boost there must be support at the file system level. If this does not exist then the system must enumerate every single object in the directory.
In principle, you can use FindFirstFileEx specifying the FindExSearchLimitToDirectories flag. However, the documentation states (emphasis mine):
This is an advisory flag. If the file system supports directory filtering, the function searches for a file that matches the specified name and is also a directory. If the file system does not support directory filtering, this flag is silently ignored.
If directory filtering is desired, this flag can be used on all file systems, but because it is an advisory flag and only affects file systems that support it, the application must examine the file attribute data stored in the lpFindFileData parameter of the FindFirstFileEx function to determine whether the function has returned a handle to a directory.
However, from what I can tell, and information is sparse, FindExSearchLimitToDirectories flag is not widely supported on desktop file systems.
Your best bet is to use FindFirstFileEx with FindExSearchLimitToDirectories. You must still perform your own filtering in case you meet a file system that doesn't support directory filtering at file system level. If you get lucky and hit upon a file system that does support it then you will get the performance benefit.
If you're using FindFirstFileEx, then you should be able to specify the _FINDEX_SEARCH_OPS::FindExSearchLimitToDirectories option (to be used as the fSearchOp param in FindFirstFileEx) to limit the first search (and any subsequent FindNextFile()) calls to directories.