How to walk through directory tree step by step? - c++

I found many examples on walking through directory tree, but I need something a little different. I need a class with some method which each call returns one file from directory and gradually walking through directory tree. How can I do this please? I am using functions FindFirstFile, FindNextFile and FindClose, I am newbie in c++. I have something like this...
For example I have this simple directory tree
Parent(folder)\
file1.txt
file2.txt
Child(folder)\
file3.txt
file4.txt
and I need a class with a method for example getNextFile(), that first call returns file1.txt; second call returns file2.txt, third call returns Child(folder), fourth call returns file3.txt and so on...
Edit on duplicate flag: I basically need walk through tree without do/while, while or for...I need some kind of iterator, which can be stored for later use and which can continue from last file, when I interrupt browsing, but ideally only with using winapi calls
WIN32_FIND_DATA fdFile;
HANDLE hFind = NULL;
if((hFind = FindFirstFile(sPath, &fdFile)) == INVALID_HANDLE_VALUE)
{
return false;
}
do
{
//do some job with fdFile
}
while(FindNextFile(hFind, &fdFile));

Here is the native C++ way of doing it on Windows platform (using MFC framework):
void ListFiles(const CString& sPath)
{
CFileFind finder;
CString sWildcard(sPath);
sWildcard += _T("\\*.*");
BOOL bWorking = finder.FindFile(sWildcard);
while (bWorking)
{
bWorking = finder.FindNextFile();
if (finder.IsDots())
continue;
if (finder.IsDirectory())
{
CString sFilePath = finder.GetFilePath();
// TODO: do stuff here
ListFiles(sFilePath);
}
}
finder.Close();
}
You can change wild card string to target specific files, like *.txt etc. You can also pass it as a parameter to this function to make it more general purpose.

Use the right tools. Boost is available as good as everywhere, and has the methods you want.
From http://rosettacode.org/wiki/Walk_a_directory/Recursively#C.2B.2B:
#include "boost/filesystem.hpp"
#include "boost/regex.hpp"
#include <iostream>
using namespace boost::filesystem;
int main()
{
path current_dir("."); //
boost::regex pattern("a.*"); // list all files starting with a
for (recursive_directory_iterator iter(current_dir), end;
iter != end;
++iter)
{
std::string name = iter->path().filename().string();
if (regex_match(name, pattern))
std::cout << iter->path() << "\n";
}
}
remove the whole regex business if you don't care whether your file matches a certain pattern.
EDIT:
Could you please explain why it would be bad to use directly API calls ?
it's ugly and hard to read, even harder to get right,
it's not portable at all, and what's most important,
there's a million corner cases you'd have to take care of, possibly, when using the raw win api. Boost has been written by people who did this a few hundred times and has underwent serious code review, so take the save route, and don't reinvent a wheel.
In essence, winapi is about two decades old; there's been a lot of usability improvement in the rest of the world. Unless you have a really good reason, I would try to abstract as much of it away as possible by using common libraries, such as Boost.
I think this does not solves my problem, I edited the original post to make it clearer.
basically need walk through tree without do/while, while or for...I need some kind of iterator, which can be stored for later use
That's exactly what my answer does: give you an Iterator in a for loop. I don't understand what's not fulfilling your Edit's specification about that.
In addition, it would be best to use only WinAPI, because it has to work on different computers with windows and installing boost could be a problem.
You don't have to install boost on any of these computers. Boost::filesystem can comfortable be linked in statically; also, the old-school windows way of doing this is just delivering boost_filesystem*.dll and boost_system*.dll along with your binary. However, if your goal is a single executable that contains all needed functions, you'll go for static linkage, anyway, so this is absolutely no problem.

Related

The equivelant code %SystemDrive% in batch translated into C++

To anyone that can help Please,
(My operating system is Windows XP)
I have looked on the this forum but have not found a similair answer that I could use or adapt to suite this particular situation. I will try to explain (I apologise in advance if my question seems confusing)
I am constructing a batch file that will call a C++ program (.exe) The C++ program is hard coded to the C: drive. By the way I did not write the C++ program as I am incapable of writing in C++ but would like to exchange the C: in C++ for what would be in batch %SystemDrive%. The line of code in C++ reads as follows:
SetSfcFileException(0, L"c:\\windows\\system32\\calc.exe",-1);
// Now we can modify the system file in a complete stealth.
}
The bit of code I would like to alter in the above code is C: or "C" to change it to %systemDrive% but in C++ code language, in effect change the hard coded part of the C++ program to read a System path variable within XP.
I have also looked elsewhere on the net but have not found a suitable answer as I do Not want to break the C++ code you see.
The C++ code was obtained from the folowing website written by Abdellatif_El_Khlifi:
https://www.codeproject.com/Articles/14933/A-simple-way-to-hack-Windows-File-Protection-WFP-u
Many Thanks for any help given,
David
The search term you should be looking for is Known Folders.
Specifically, calling SHGetKnownFolderPath() with the FOLDERID_System identifier, one of the many IDs found here.
That's for Vista or better. For earlier than that (such as XP), you have to use CSIDL values, CSIDL_SYSTEM (see here for list) passed into SHGetFolderPath().
You can still use the pre-Vista ones but I think they're just thin wrappers around the newer ones.
This is the simplest console application I could come up with that shows this in action (Visual Studio 2019):
#include <iostream>
#include <shlobj_core.h>
#include <comutil.h>
int main()
{
PWSTR path = NULL;
HRESULT hr = SHGetKnownFolderPath(FOLDERID_System, 0, NULL, &path);
_bstr_t bstrPath(path);
std::string strPath((char*)bstrPath);
std::cout << "Path is '" << strPath << "'\n";
}
and the output on my system is:
Path is 'C:\WINDOWS\system32'
This is not really answering my own question, well it is but in a alternative manner, many ways to skin a cat so to speak!
Here is one encouraging bit of news though I have stumbled across the very thing I need called WFPReplacer, it is a commandline windows utility that pretty well does what I want & generally in the same manner. it disables WFP for both singular files & can be used for wholesale switching off of WFP if the right file is replaced. All I need to do is write a batch file as a front end to back up the system files I want to disable use WFPReplacer.exe. So if in the event of the proceedings the routine gets stuffed I can revert back to the backed up files. I think this program uses the same type of embedded coding but is written in Delphi/pascal, it is called Remko Weijnen's Blog (Remko's Blog) "replacing Wfp protected files".
I generally like to leave whatever I am doing on a positive note. So just in case someone else lands on this forum & is trying to accomplish a similair exercise here is the code that one can compile (This is not my code it belongs to Remko Weijnen's Blog (Remko's Blog)) Please be advised it is NOT C++ it is a commandline exe Delhi/Pascal found at this link, so all credits belong to him. The link is:
https://www.remkoweijnen.nl/blog/2012/12/05/replacing-wfp-protected-files/
DWORD __stdcall SfcFileException(RPC_BINDING_HANDLE hServer, LPCWSTR lpSrc, int Unknown)
{
RPC_BINDING_HANDLE hServerVar; // eax#2
int nts; // eax#6
__int32 dwResult; // eax#7
DWORD dwResultVar; // esi#9
int v8; // [sp+8h] [bp-8h]#1
int v9; // [sp+Ch] [bp-4h]#1
LOWORD(v8) = 0;
*(int *)((char *)&v8 + 2) = 0;
HIWORD(v9) = 0;
if ( !hServer )
{
hServerVar = _pRpcHandle;
if ( !_pRpcHandle )
{
hServerVar = SfcConnectToServer(0);
_pRpcHandle = hServerVar;
if ( !hServerVar )
return 0x6BA; // RPC_S_SERVER_UNAVAILABLE
}
hServer = hServerVar;
}
nts = SfcRedirectPath(lpSrc, (int)&v8);
if ( nts >= 0 )
dwResult = SfcCli_FileException((int)hServer, v9, Unknown).Simple;
else
dwResult = RtlNtStatusToDosError(nts);
dwResultVar = dwResult;
MemFree(v9);
return dwResultVar;
}
Also as one further warning (Unless you know what you are doing!!!) do not attempt to use this program, ALWAYS ALWAYS ALWAYS backup your system files before deletion or alteration.
What this program will do is disarm WFP for 60 seconds whilst you intercange or amend your files. Example usage for example is:
WfpReplacer.exe c:\windows\Notepad.exe (Errorlevel true or false will be produced on execution).
Best Regards
David

A system function to convert relative path to full path that works even for non-exsting paths?

This question has been asked before, but pretty much all the answers boil down to the realpath function. Which doesn't work for paths that do not exist. I need a solution that will, and I want to call a POSIX or OS X framework function rather than hand-parse strings.
To reiterate: I need a function that takes an arbitrary path string and returns the equivalent path with no "./" or ".." elements.
Is there such a solution?
Are you sure there can be such a solution? I believe that not (because some directories could be typos or symbolic links to be created).
What do you expect your betterrealpath function to return for /tmp/someinexistentdirectory/foobar ? Perhaps the user intent was a symbolic link from his $HOME to /tmp/someinexistentdirectory ? Or perhaps it is a typo and the user wants /tmp/someexistentdirectory/foobar ...? And what about /tmp/someinexistentdirectory/../foobar? Should it be canonicalized as /tmp/foobar? Why?
Maybe using first dirname(3), then doing realpath(3) on that, then appending the basename(3) of the argument should be enough? In C something like:
const char*origpath = something();
char*duppath = strdup(origpath);
if (!duppath) { perror("strdup"); exit(EXIT_FAILURE); };
char*basepath = basename(duppath);
char*dirpath = dirname(duppath);
char*realdirpath = realpath(dirpath, NULL);
if (!realdirpath) { perror("realpath"); exit(EXIT_FAILURE); };
char* canonpath = NULL;
if (asprintf(&canonpath, "%s/%s", realdirpath, basepath) <= 0)
{ perror("asprintf"); exit(EXIT_FAILURE); };
free (duppath), duppath = NULL;
basepath = NULL, dirpath = NULL;
/// use canonpath below, don't forget to free it
Of course that example won't work for /tmp/someinexistentdirectory/foobar but would work for /home/violet/missingfile, assuming your home directory is /home/violet/ and is accessible (readable & executable) ...
Feel free to improve or adapt to C++ the above code. Don't forget to handle failures.
Remember that i-nodes are central to POSIX filesystems. A file (including a directory) can have one, zero, or several file paths... A directory (or a file) name can be rename-d by some other running process...
Perhaps you want to use a framework like Qt or POCO; they might provide something good enough for you...
Actually, I suggest you to code your betterrealpath function entirely yourself, using only syscalls(2) on Linux. You'll then have to think about all the weird cases... Also, use strace(1) on realpath(1) to understand what it is doing...
Alternatively, don't care about non-canonical paths containing ../ or symbol links in directories, and simply prepend the current directory (see getcwd(3)) to any path not starting with / .......

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.

How to know and load all images in a specific folder?

I have an application (C++ Builder 6.0) that needs to know the total of images there are in a specific folder, and then I have to load them: in an ImageList or in a ComboBoxEx... or any other control...
How can I do that?
I know how to load an image in a control, or to save in a TList, or in an ImageList... but How to know how many files files there are in the directory, and how to load every image in it??
I am Sorry about my English.
I did something like this yesterday with C++ using the boost::filesystem library. However, if you are not using boost already, I would strongly recommend you just use the windows libraries instead. This was my code though in case you're interested:
#include <algorithm>
#include <boost/filesystem.hpp>
#include <set>
namespace fs = boost::filesystem;
typedef std::vector<fs::path> PathVector;
std::auto_ptr<PathVector> ImagesInFolder(const fs::path& folderPath) {
std::set<std::string> targetExtensions;
targetExtensions.insert(".JPG");
targetExtensions.insert(".BMP");
targetExtensions.insert(".GIF");
targetExtensions.insert(".PNG");
std::auto_ptr<PathVector> paths(new PathVector());
fs::directory_iterator end;
for(fs::directory_iterator iter(folderPath); iter != end; ++iter) {
if(!fs::is_regular_file(iter->status())) { continue; }
std::string extension = iter->path().extension();
std::transform(extension.begin(), extension.end(), extension.begin(), ::toupper);
if(targetExtensions.find(extension) == targetExtensions.end()) { continue; }
paths->push_back(iter->path());
}
return paths;
}
This doesn't answer the part of your question about how to actually put the paths into a listbox though.
Use the Win32 functions FindFirstFile and FindNextFile ...?
There's no practical way to identify every image in an arbitrary folder. Almost anything you can't identify as something else, could be some sort of image. Then again, using steganography, even something you can identify as something else still might be (or contain) at least part of an image as well.
Realistically, you want to pick out a set of formats you want to support, and write code that knows about them. For quite a few purposes, a half dozen formats or so is quite adequate, though the exact half dozen you pick will vary by the type of application -- only a few programs have any use for both bitmapped and vector graphics, for one example.
Once you've decided what you want, DlgDirList is probably the easiest way to list some files. If that isn't flexible enough for your purposes, the next obvious choice is FindFirstFile, FindNextFile, and FindClose.
To get a list of all files in a folder, have a look at the FindFirst and FindNext functions in SysUtils.
Here is an example function which shows how to get a list of files.
void __fastcall TForm1::GetDirList(TStrings *List, const AnsiString SearchStr)
{
TSearchRec SRec;
AnsiString TempFName;
List->Clear();
// start search
if (FindFirst(SearchStr, faAnyFile, SRec) == 0)
{
do
{
if ((SRec.Attr & faDirectory) != faDirectory) // exclude directories
{
List->Add(SRec.Name);
} // end if
}
while (FindNext(SRec) == 0);
FindClose(SRec);
} // end if
}
Examples:
// get list of all files in directory
GetDirList(MyStringList, "C:\images*.*");
// get list of all .bmp files in directory
GetDirList(MyStringList, "C:\images\*.bmp");
If you can upgrade to newer version of C++Builder, have a look at TMS AdvSmoothImageListBox, from TMS Software.
The TMS Smooth Controls are available free for C++Builder 2010 users on the from Embarcadero website.

Parse config file in C/C++

I'm a newbie looking for a fast and easy way to parse a text file in C or C++ (wxWidgets)
The file will look something like this (A main category with "sub-objects") which will appear in a list box
[CategoryA]
[SubCat]
Str1 = Test
Str2 = Description
[SubCat] [End]
[SubCat]
Str1 = Othertest
...
[CategoryA] [End]
Any suggestions?
Sounds like you want to parse a file that's pretty close to an ini file.
There's at least a few INI parser libraries out there: minIni, iniParser, libini, for instance.
It should be fairly easy to write your own parser for this if you use streams. You can read a file using an std::ifstream:
std::ifstream ifs("filename.ext");
if(!ifs.good()) throw my_exceptions("cannot open file");
read_file(ifs);
Since it seems line-oriented, you would then first read lines, and then process these:
void read_file(std::istream& is)
{
for(;;) {
std::string line;
std::getline(is, line);
if(!is) break;
std::istringstream iss(line);
// read from iss
}
if(!is.eof()) throw my_exceptions("error reading file");
}
For the actual parsing, you could 1) first peek at the first character. If that's a [, pop it from the stream, and use std::getline(is,identifier,']') to read whatever is within '[' and ']'. If it isn't a [, use std::getline(is, key, '=') to read the left side of a key-value pair, and then std::getline(is, value) to read the right side.
Note: Stream input, unfortunately, is usually not exactly lightning fast. (This doesn't have to be that way, but in practice this often is.) However, it is really easy to do and it is fairly easy to do it right, once you know a very few patterns to work with its peculiarities (like if(strm.good()) not being the same as if(strm) and not being the opposite of if(strm.bad()) and a few other things you'll have to get used to). For something as performance-critical (har har!) as reading an ini file from disk, it should be fast enough in 999,999 out of 1,000,000 cases.
You may want to try Boost.Program_Options. However it has slightly different formatting. More close to INI files. Subcategories are done like this:
[CategoryA]
Option = Data
[CategoryB.Subcategory1]
Option = Data
[CategoryB.Subcategory2]
Option = Data
Also it has some other features so it is actually very useful IMO.
Try Configurator. It's easy-to-use and flexible C++ library for configuration file parsing (from simplest INI to complex files with arbitrary nesting and semantic checking). Header-only and cross-platform. Uses Boost C++ libraries.
See: http://opensource.dshevchenko.biz/configurator
It looks more straightforward to implement your own parser than to try to adapt an existing one you are unfamiliar with.
Your structure seems - from your example - to be line-based. This makes parsing it easy.
It generally makes sense to load your file into a tree, and then walk around it as necessary.
On Windows only, GetPrivateProfileSection does this. It's deprecated in favor of the registry but it's still here and it still works.
How about trying to make a simple XML file? There are plenty of libraries that can help you read it, and the added bonus is that a lot of other programs/languages can read it too.
If you're using wxWidgets I would consider wxFileConfig. I'm not using wxWidgets, but the class seems to support categories with sub-categories.
When you are using GTK, you are lucky.
You can use the Glib KeyFile save_to_file and load_from_file.
https://docs.gtk.org/glib/struct.KeyFile.html
Or when using Gtkmm (C++).
See: https://developer-old.gnome.org/glibmm/stable/classGlib_1_1KeyFile.html
Example in C++ with load_from_file:
#include <glibmm.h>
#include <string>
Glib::KeyFile keyfile;
keyfile.load_from_file(file_path);
std::string path = keyfile.get_string("General", "Path");
bool is_enabled = keyfile.get_boolean("General", "IsEnabled");
Saving is as easy as calling save_to_file:
Glib::KeyFile keyfile;
keyfile.set_string("General", "Path", path);
keyfile.set_boolean("General", "IsEnabled", is_enabled);
keyfile.save_to_file(file_path);