How can I create directory tree in C++/Linux? - c++

I want an easy way to create multiple directories in C++/Linux.
For example I want to save a file lola.file in the directory:
/tmp/a/b/c
but if the directories are not there I want them to be created automagically. A working example would be perfect.

Easy with Boost.Filesystem: create_directories
#include <boost/filesystem.hpp>
//...
boost::filesystem::create_directories("/tmp/a/b/c");
Returns: true if a new directory was created, otherwise false.

With C++17 or later, there's the standard header <filesystem> with
function
std::filesystem::create_directories
which should be used in modern C++ programs.
The C++ standard functions do not have the POSIX-specific explicit
permissions (mode) argument, though.
However, here's a C function that can be compiled with C++ compilers.
/*
#(#)File: mkpath.c
#(#)Purpose: Create all directories in path
#(#)Author: J Leffler
#(#)Copyright: (C) JLSS 1990-2020
#(#)Derivation: mkpath.c 1.16 2020/06/19 15:08:10
*/
/*TABSTOP=4*/
#include "posixver.h"
#include "mkpath.h"
#include "emalloc.h"
#include <errno.h>
#include <string.h>
/* "sysstat.h" == <sys/stat.h> with fixup for (old) Windows - inc mode_t */
#include "sysstat.h"
typedef struct stat Stat;
static int do_mkdir(const char *path, mode_t mode)
{
Stat st;
int status = 0;
if (stat(path, &st) != 0)
{
/* Directory does not exist. EEXIST for race condition */
if (mkdir(path, mode) != 0 && errno != EEXIST)
status = -1;
}
else if (!S_ISDIR(st.st_mode))
{
errno = ENOTDIR;
status = -1;
}
return(status);
}
/**
** mkpath - ensure all directories in path exist
** Algorithm takes the pessimistic view and works top-down to ensure
** each directory in path exists, rather than optimistically creating
** the last element and working backwards.
*/
int mkpath(const char *path, mode_t mode)
{
char *pp;
char *sp;
int status;
char *copypath = STRDUP(path);
status = 0;
pp = copypath;
while (status == 0 && (sp = strchr(pp, '/')) != 0)
{
if (sp != pp)
{
/* Neither root nor double slash in path */
*sp = '\0';
status = do_mkdir(copypath, mode);
*sp = '/';
}
pp = sp + 1;
}
if (status == 0)
status = do_mkdir(path, mode);
FREE(copypath);
return (status);
}
#ifdef TEST
#include <stdio.h>
#include <unistd.h>
/*
** Stress test with parallel running of mkpath() function.
** Before the EEXIST test, code would fail.
** With the EEXIST test, code does not fail.
**
** Test shell script
** PREFIX=mkpath.$$
** NAME=./$PREFIX/sa/32/ad/13/23/13/12/13/sd/ds/ww/qq/ss/dd/zz/xx/dd/rr/ff/ff/ss/ss/ss/ss/ss/ss/ss/ss
** : ${MKPATH:=mkpath}
** ./$MKPATH $NAME &
** [...repeat a dozen times or so...]
** ./$MKPATH $NAME &
** wait
** rm -fr ./$PREFIX/
*/
int main(int argc, char **argv)
{
int i;
for (i = 1; i < argc; i++)
{
for (int j = 0; j < 20; j++)
{
if (fork() == 0)
{
int rc = mkpath(argv[i], 0777);
if (rc != 0)
fprintf(stderr, "%d: failed to create (%d: %s): %s\n",
(int)getpid(), errno, strerror(errno), argv[i]);
exit(rc == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
}
}
int status;
int fail = 0;
while (wait(&status) != -1)
{
if (WEXITSTATUS(status) != 0)
fail = 1;
}
if (fail == 0)
printf("created: %s\n", argv[i]);
}
return(0);
}
#endif /* TEST */
The macros STRDUP() and FREE() are error-checking versions of
strdup() and free(), declared in emalloc.h (and implemented in
emalloc.c and estrdup.c).
The "sysstat.h" header deals with broken versions of <sys/stat.h>
and can be replaced by <sys/stat.h> on modern Unix systems (but there
were many issues back in 1990).
And "mkpath.h" declares mkpath().
The change between v1.12 (original version of the answer) and v1.13
(amended version of the answer) was the test for EEXIST in
do_mkdir().
This was pointed out as necessary by
Switch — thank
you, Switch.
The test code has been upgraded and reproduced the problem on a MacBook
Pro (2.3GHz Intel Core i7, running Mac OS X 10.7.4), and suggests that
the problem is fixed in the revision (but testing can only show the
presence of bugs, never their absence).
The code shown is now v1.16; there have been cosmetic or administrative
changes made since v1.13 (such as use mkpath.h instead of jlss.h and
include <unistd.h> unconditionally in the test code only).
It's reasonable to argue that "sysstat.h" should be replaced by
<sys/stat.h> unless you have an unusually recalcitrant system.
(You are hereby given permission to use this code for any purpose with attribution.)
This code is available in my SOQ
(Stack Overflow Questions) repository on GitHub as files mkpath.c and
mkpath.h (etc.) in the
src/so-0067-5039
sub-directory.

system("mkdir -p /tmp/a/b/c")
is the shortest way I can think of (in terms of the length of code, not necessarily execution time).
It's not cross-platform but will work under Linux.

Here is my example of code (it works for both Windows and Linux):
#include <iostream>
#include <string>
#include <sys/stat.h> // stat
#include <errno.h> // errno, ENOENT, EEXIST
#if defined(_WIN32)
#include <direct.h> // _mkdir
#endif
bool isDirExist(const std::string& path)
{
#if defined(_WIN32)
struct _stat info;
if (_stat(path.c_str(), &info) != 0)
{
return false;
}
return (info.st_mode & _S_IFDIR) != 0;
#else
struct stat info;
if (stat(path.c_str(), &info) != 0)
{
return false;
}
return (info.st_mode & S_IFDIR) != 0;
#endif
}
bool makePath(const std::string& path)
{
#if defined(_WIN32)
int ret = _mkdir(path.c_str());
#else
mode_t mode = 0755;
int ret = mkdir(path.c_str(), mode);
#endif
if (ret == 0)
return true;
switch (errno)
{
case ENOENT:
// parent didn't exist, try to create it
{
int pos = path.find_last_of('/');
if (pos == std::string::npos)
#if defined(_WIN32)
pos = path.find_last_of('\\');
if (pos == std::string::npos)
#endif
return false;
if (!makePath( path.substr(0, pos) ))
return false;
}
// now, try to create again
#if defined(_WIN32)
return 0 == _mkdir(path.c_str());
#else
return 0 == mkdir(path.c_str(), mode);
#endif
case EEXIST:
// done!
return isDirExist(path);
default:
return false;
}
}
int main(int argc, char* ARGV[])
{
for (int i=1; i<argc; i++)
{
std::cout << "creating " << ARGV[i] << " ... " << (makePath(ARGV[i]) ? "OK" : "failed") << std::endl;
}
return 0;
}
Usage:
$ makePath 1/2 folderA/folderB/folderC
creating 1/2 ... OK
creating folderA/folderB/folderC ... OK

#include <sys/types.h>
#include <sys/stat.h>
int status;
...
status = mkdir("/tmp/a/b/c", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
From here. You may have to do separate mkdirs for /tmp, /tmp/a, /tmp/a/b/ and then /tmp/a/b/c because there isn't an equivalent of the -p flag in the C api. Be sure and ignore the EEXISTS errno while you're doing the upper level ones.

It should be noted that starting from C++17 filesystem interface is part of the standard library. This means that one can have following to create directories:
#include <filesystem>
std::filesystem::create_directories("/a/b/c/d")
More info here: https://en.cppreference.com/w/cpp/filesystem/create_directory
Additionally, with gcc, one needs to "-std=c++17" to CFLAGS. And "-lstdc++fs" to LDLIBS. The latter potentially is not going to be required in the future.

This is similar to the previous but works forward through the string instead of recursively backwards. Leaves errno with the right value for last failure. If there's a leading slash, there's an extra time through the loop which could have been avoided via one find_first_of() outside the loop or by detecting the leading / and setting pre to 1. The efficiency is the same whether we get set up by a first loop or a pre loop call, and the complexity would be (slightly) higher when using the pre-loop call.
#include <iostream>
#include <string>
#include <sys/stat.h>
int
mkpath(std::string s,mode_t mode)
{
size_t pos=0;
std::string dir;
int mdret;
if(s[s.size()-1]!='/'){
// force trailing / so we can handle everything in loop
s+='/';
}
while((pos=s.find_first_of('/',pos))!=std::string::npos){
dir=s.substr(0,pos++);
if(dir.size()==0) continue; // if leading / first time is 0 length
if((mdret=mkdir(dir.c_str(),mode)) && errno!=EEXIST){
return mdret;
}
}
return mdret;
}
int main()
{
int mkdirretval;
mkdirretval=mkpath("./foo/bar",0755);
std::cout << mkdirretval << '\n';
}

You said "C++" but everyone here seems to be thinking "Bash shell."
Check out the source code to gnu mkdir; then you can see how to implement the shell commands in C++.

bool mkpath( std::string path )
{
bool bSuccess = false;
int nRC = ::mkdir( path.c_str(), 0775 );
if( nRC == -1 )
{
switch( errno )
{
case ENOENT:
//parent didn't exist, try to create it
if( mkpath( path.substr(0, path.find_last_of('/')) ) )
//Now, try to create again.
bSuccess = 0 == ::mkdir( path.c_str(), 0775 );
else
bSuccess = false;
break;
case EEXIST:
//Done!
bSuccess = true;
break;
default:
bSuccess = false;
break;
}
}
else
bSuccess = true;
return bSuccess;
}

So I need mkdirp() today, and found the solutions on this page overly complicated.
Hence I wrote a fairly short snippet, that easily be copied in for others who
stumble upon this thread an wonder why we need so many lines of code.
mkdirp.h
#ifndef MKDIRP_H
#define MKDIRP_H
#include <sys/stat.h>
#define DEFAULT_MODE S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH
/** Utility function to create directory tree */
bool mkdirp(const char* path, mode_t mode = DEFAULT_MODE);
#endif // MKDIRP_H
mkdirp.cpp
#include <errno.h>
bool mkdirp(const char* path, mode_t mode) {
// const cast for hack
char* p = const_cast<char*>(path);
// Do mkdir for each slash until end of string or error
while (*p != '\0') {
// Skip first character
p++;
// Find first slash or end
while(*p != '\0' && *p != '/') p++;
// Remember value from p
char v = *p;
// Write end of string at p
*p = '\0';
// Create folder from path to '\0' inserted at p
if(mkdir(path, mode) == -1 && errno != EEXIST) {
*p = v;
return false;
}
// Restore path to it's former glory
*p = v;
}
return true;
}
If you don't like const casting and temporarily modifying the string, just do a strdup() and free() it afterwards.

Since this post is ranking high in Google for "Create Directory Tree", I am going to post an answer that will work for Windows — this will work using Win32 API compiled for UNICODE or MBCS. This is ported from Mark's code above.
Since this is Windows we are working with, directory separators are BACK-slashes, not forward slashes. If you would rather have forward slashes, change '\\' to '/'
It will work with:
c:\foo\bar\hello\world
and
c:\foo\bar\hellp\world\
(i.e.: does not need trailing slash, so you don't have to check for it.)
Before saying "Just use SHCreateDirectoryEx() in Windows", note that SHCreateDirectoryEx() is deprecated and could be removed at any time from future versions of Windows.
bool CreateDirectoryTree(LPCTSTR szPathTree, LPSECURITY_ATTRIBUTES lpSecurityAttributes = NULL){
bool bSuccess = false;
const BOOL bCD = CreateDirectory(szPathTree, lpSecurityAttributes);
DWORD dwLastError = 0;
if(!bCD){
dwLastError = GetLastError();
}else{
return true;
}
switch(dwLastError){
case ERROR_ALREADY_EXISTS:
bSuccess = true;
break;
case ERROR_PATH_NOT_FOUND:
{
TCHAR szPrev[MAX_PATH] = {0};
LPCTSTR szLast = _tcsrchr(szPathTree,'\\');
_tcsnccpy(szPrev,szPathTree,(int)(szLast-szPathTree));
if(CreateDirectoryTree(szPrev,lpSecurityAttributes)){
bSuccess = CreateDirectory(szPathTree,lpSecurityAttributes)!=0;
if(!bSuccess){
bSuccess = (GetLastError()==ERROR_ALREADY_EXISTS);
}
}else{
bSuccess = false;
}
}
break;
default:
bSuccess = false;
break;
}
return bSuccess;
}

I know it's an old question but it shows up high on google search results and the answers provided here are not really in C++ or are a bit too complicated.
Please note that in my example createDirTree() is very simple because all the heavy lifting (error checking, path validation) needs to be done by createDir() anyway. Also createDir() should return true if directory already exists or the whole thing won't work.
Here's how I would do that in C++:
#include <iostream>
#include <string>
bool createDir(const std::string dir)
{
std::cout << "Make sure dir is a valid path, it does not exist and create it: "
<< dir << std::endl;
return true;
}
bool createDirTree(const std::string full_path)
{
size_t pos = 0;
bool ret_val = true;
while(ret_val == true && pos != std::string::npos)
{
pos = full_path.find('/', pos + 1);
ret_val = createDir(full_path.substr(0, pos));
}
return ret_val;
}
int main()
{
createDirTree("/tmp/a/b/c");
return 0;
}
Of course createDir() function will be system-specific and there are already enough examples in other answers how to write it for linux, so I decided to skip it.

So many approaches has been described here but most of them need hard coding of your path into your code.
There is an easy solution for that problem, using QDir and QFileInfo, two classes of Qt framework. Since your already in Linux environment it should be easy to use Qt.
QString qStringFileName("path/to/the/file/that/dont/exist.txt");
QDir dir = QFileInfo(qStringFileName).dir();
if(!dir.exists()) {
dir.mkpath(dir.path());
}
Make sure you have write access to that Path.

If dir does not exist, create it:
boost::filesystem::create_directories(boost::filesystem::path(output_file).parent_path().string().c_str());

Here's C/C++ recursive function that makes use of dirname() to traverse bottom-up the directory tree. It will stop as soon as it finds an existing ancestor.
#include <libgen.h>
#include <string.h>
int create_dir_tree_recursive(const char *path, const mode_t mode)
{
if (strcmp(path, "/") == 0) // No need of checking if we are at root.
return 0;
// Check whether this dir exists or not.
struct stat st;
if (stat(path, &st) != 0 || !S_ISDIR(st.st_mode))
{
// Check and create parent dir tree first.
char *path2 = strdup(path);
char *parent_dir_path = dirname(path2);
if (create_dir_tree_recursive(parent_dir_path, mode) == -1)
return -1;
// Create this dir.
if (mkdir(path, mode) == -1)
return -1;
}
return 0;
}

mkdir -p /dir/to/the/file
touch /dir/to/the/file/thefile.ending

If you don't have C++17 yet and look for a platform agnostic solution, use ghc::filesystem. The header-ony code is compatible to C++17 (in fact a backport) and easy to migrate later on.

The others got you the right answer, but I thought I'd demonstrate another neat thing you can do:
mkdir -p /tmp/a/{b,c}/d
Will create the following paths:
/tmp/a/b/d
/tmp/a/c/d
The braces allow you to create multiple directories at once on the same level of the hierarchy, whereas the -p option means "create parent directories as needed".

Related

Go through all files in a directory [duplicate]

How do you iterate through every file/directory recursively in standard C++?
From C++17 onward, the <filesystem> header, and range-for, you can simply do this:
#include <filesystem>
using recursive_directory_iterator = std::filesystem::recursive_directory_iterator;
...
for (const auto& dirEntry : recursive_directory_iterator(myPath))
std::cout << dirEntry << std::endl;
As of C++17, std::filesystem is part of the standard library and can be found in the <filesystem> header (no longer "experimental").
In standard C++, technically there is no way to do this since standard C++ has no conception of directories. If you want to expand your net a little bit, you might like to look at using Boost.FileSystem. This has been accepted for inclusion in TR2, so this gives you the best chance of keeping your implementation as close as possible to the standard.
An example, taken straight from the website:
bool find_file( const path & dir_path, // in this directory,
const std::string & file_name, // search for this name,
path & path_found ) // placing path here if found
{
if ( !exists( dir_path ) ) return false;
directory_iterator end_itr; // default construction yields past-the-end
for ( directory_iterator itr( dir_path );
itr != end_itr;
++itr )
{
if ( is_directory(itr->status()) )
{
if ( find_file( itr->path(), file_name, path_found ) ) return true;
}
else if ( itr->leaf() == file_name ) // see below
{
path_found = itr->path();
return true;
}
}
return false;
}
If using the Win32 API you can use the FindFirstFile and FindNextFile functions.
http://msdn.microsoft.com/en-us/library/aa365200(VS.85).aspx
For recursive traversal of directories you must inspect each WIN32_FIND_DATA.dwFileAttributes to check if the FILE_ATTRIBUTE_DIRECTORY bit is set. If the bit is set then you can recursively call the function with that directory. Alternatively you can use a stack for providing the same effect of a recursive call but avoiding stack overflow for very long path trees.
#include <windows.h>
#include <string>
#include <vector>
#include <stack>
#include <iostream>
using namespace std;
bool ListFiles(wstring path, wstring mask, vector<wstring>& files) {
HANDLE hFind = INVALID_HANDLE_VALUE;
WIN32_FIND_DATA ffd;
wstring spec;
stack<wstring> directories;
directories.push(path);
files.clear();
while (!directories.empty()) {
path = directories.top();
spec = path + L"\\" + mask;
directories.pop();
hFind = FindFirstFile(spec.c_str(), &ffd);
if (hFind == INVALID_HANDLE_VALUE) {
return false;
}
do {
if (wcscmp(ffd.cFileName, L".") != 0 &&
wcscmp(ffd.cFileName, L"..") != 0) {
if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
directories.push(path + L"\\" + ffd.cFileName);
}
else {
files.push_back(path + L"\\" + ffd.cFileName);
}
}
} while (FindNextFile(hFind, &ffd) != 0);
if (GetLastError() != ERROR_NO_MORE_FILES) {
FindClose(hFind);
return false;
}
FindClose(hFind);
hFind = INVALID_HANDLE_VALUE;
}
return true;
}
int main(int argc, char* argv[])
{
vector<wstring> files;
if (ListFiles(L"F:\\cvsrepos", L"*", files)) {
for (vector<wstring>::iterator it = files.begin();
it != files.end();
++it) {
wcout << it->c_str() << endl;
}
}
return 0;
}
You can make it even simpler with the new C++11 range based for and Boost:
#include <boost/filesystem.hpp>
using namespace boost::filesystem;
struct recursive_directory_range
{
typedef recursive_directory_iterator iterator;
recursive_directory_range(path p) : p_(p) {}
iterator begin() { return recursive_directory_iterator(p_); }
iterator end() { return recursive_directory_iterator(); }
path p_;
};
for (auto it : recursive_directory_range(dir_path))
{
std::cout << it << std::endl;
}
A fast solution is using C's Dirent.h library.
Working code fragment from Wikipedia:
#include <stdio.h>
#include <dirent.h>
int listdir(const char *path) {
struct dirent *entry;
DIR *dp;
dp = opendir(path);
if (dp == NULL) {
perror("opendir: Path does not exist or could not be read.");
return -1;
}
while ((entry = readdir(dp)))
puts(entry->d_name);
closedir(dp);
return 0;
}
You can use std::filesystem::recursive_directory_iterator. But beware, this includes symbolic (soft) links. If you want to avoid them you can use is_symlink. Example usage:
size_t directory_size(const std::filesystem::path& directory)
{
size_t size{ 0 };
for (const auto& entry : std::filesystem::recursive_directory_iterator(directory))
{
if (entry.is_regular_file() && !entry.is_symlink())
{
size += entry.file_size();
}
}
return size;
}
In addition to the above mentioned boost::filesystem you may want to examine wxWidgets::wxDir and Qt::QDir.
Both wxWidgets and Qt are open source, cross platform C++ frameworks.
wxDir provides a flexible way to traverse files recursively using Traverse() or a simpler GetAllFiles() function. As well you can implement the traversal with GetFirst() and GetNext() functions (I assume that Traverse() and GetAllFiles() are wrappers that eventually use GetFirst() and GetNext() functions).
QDir provides access to directory structures and their contents. There are several ways to traverse directories with QDir. You can iterate over the directory contents (including sub-directories) with QDirIterator that was instantiated with QDirIterator::Subdirectories flag. Another way is to use QDir's GetEntryList() function and implement a recursive traversal.
Here is sample code (taken from here # Example 8-5) that shows how to iterate over all sub directories.
#include <qapplication.h>
#include <qdir.h>
#include <iostream>
int main( int argc, char **argv )
{
QApplication a( argc, argv );
QDir currentDir = QDir::current();
currentDir.setFilter( QDir::Dirs );
QStringList entries = currentDir.entryList();
for( QStringList::ConstIterator entry=entries.begin(); entry!=entries.end(); ++entry)
{
std::cout << *entry << std::endl;
}
return 0;
}
Boost::filesystem provides recursive_directory_iterator, which is quite convenient for this task:
#include "boost/filesystem.hpp"
#include <iostream>
using namespace boost::filesystem;
recursive_directory_iterator end;
for (recursive_directory_iterator it("./"); it != end; ++it) {
std::cout << *it << std::endl;
}
You can use ftw(3) or nftw(3) to walk a filesystem hierarchy in C or C++ on POSIX systems.
We are in 2019. We have filesystem standard library in C++. The Filesystem library provides facilities for performing operations on file systems and their components, such as paths, regular files, and directories.
There is an important note on this link if you are considering portability issues. It says:
The filesystem library facilities may be unavailable if a hierarchical file system is not accessible to the implementation, or if it does not provide the necessary capabilities. Some features may not be available if they are not supported by the underlying file system (e.g. the FAT filesystem lacks symbolic links and forbids multiple hardlinks). In those cases, errors must be reported.
The filesystem library was originally developed as boost.filesystem, was published as the technical specification ISO/IEC TS 18822:2015, and finally merged to ISO C++ as of C++17. The boost implementation is currently available on more compilers and platforms than the C++17 library.
#adi-shavit has answered this question when it was part of std::experimental and he has updated this answer in 2017. I want to give more details about the library and show more detailed example.
std::filesystem::recursive_directory_iterator is an LegacyInputIterator that iterates over the directory_entry elements of a directory, and, recursively, over the entries of all subdirectories. The iteration order is unspecified, except that each directory entry is visited only once.
If you don't want to recursively iterate over the entries of subdirectories, then directory_iterator should be used.
Both iterators returns an object of directory_entry. directory_entry has various useful member functions like is_regular_file, is_directory, is_socket, is_symlink etc. The path() member function returns an object of std::filesystem::path and it can be used to get file extension, filename, root name.
Consider the example below. I have been using Ubuntu and compiled it over the terminal using
g++ example.cpp --std=c++17 -lstdc++fs -Wall
#include <iostream>
#include <string>
#include <filesystem>
void listFiles(std::string path)
{
for (auto& dirEntry: std::filesystem::recursive_directory_iterator(path)) {
if (!dirEntry.is_regular_file()) {
std::cout << "Directory: " << dirEntry.path() << std::endl;
continue;
}
std::filesystem::path file = dirEntry.path();
std::cout << "Filename: " << file.filename() << " extension: " << file.extension() << std::endl;
}
}
int main()
{
listFiles("./");
return 0;
}
You would probably be best with either boost or c++14's experimental filesystem stuff. IF you are parsing an internal directory (ie. used for your program to store data after the program was closed), then make an index file that has an index of the file contents. By the way, you probably would need to use boost in the future, so if you don't have it installed, install it! Second of all, you could use a conditional compilation, e.g.:
#ifdef WINDOWS //define WINDOWS in your code to compile for windows
#endif
The code for each case is taken from https://stackoverflow.com/a/67336/7077165
#ifdef POSIX //unix, linux, etc.
#include <stdio.h>
#include <dirent.h>
int listdir(const char *path) {
struct dirent *entry;
DIR *dp;
dp = opendir(path);
if (dp == NULL) {
perror("opendir: Path does not exist or could not be read.");
return -1;
}
while ((entry = readdir(dp)))
puts(entry->d_name);
closedir(dp);
return 0;
}
#endif
#ifdef WINDOWS
#include <windows.h>
#include <string>
#include <vector>
#include <stack>
#include <iostream>
using namespace std;
bool ListFiles(wstring path, wstring mask, vector<wstring>& files) {
HANDLE hFind = INVALID_HANDLE_VALUE;
WIN32_FIND_DATA ffd;
wstring spec;
stack<wstring> directories;
directories.push(path);
files.clear();
while (!directories.empty()) {
path = directories.top();
spec = path + L"\\" + mask;
directories.pop();
hFind = FindFirstFile(spec.c_str(), &ffd);
if (hFind == INVALID_HANDLE_VALUE) {
return false;
}
do {
if (wcscmp(ffd.cFileName, L".") != 0 &&
wcscmp(ffd.cFileName, L"..") != 0) {
if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
directories.push(path + L"\\" + ffd.cFileName);
}
else {
files.push_back(path + L"\\" + ffd.cFileName);
}
}
} while (FindNextFile(hFind, &ffd) != 0);
if (GetLastError() != ERROR_NO_MORE_FILES) {
FindClose(hFind);
return false;
}
FindClose(hFind);
hFind = INVALID_HANDLE_VALUE;
}
return true;
}
#endif
//so on and so forth.
You don't. The C++ standard has no concept of directories. It is up to the implementation to turn a string into a file handle. The contents of that string and what it maps to is OS dependent. Keep in mind that C++ can be used to write that OS, so it gets used at a level where asking how to iterate through a directory is not yet defined (because you are writing the directory management code).
Look at your OS API documentation for how to do this. If you need to be portable, you will have to have a bunch of #ifdefs for various OSes.
You need to call OS-specific functions for filesystem traversal, like open() and readdir(). The C standard does not specify any filesystem-related functions.
You don't. Standard C++ doesn't expose to concept of a directory. Specifically it doesn't give any way to list all the files in a directory.
A horrible hack would be to use system() calls and to parse the results. The most reasonable solution would be to use some kind of cross-platform library such as Qt or even POSIX.
On C++17 you can by this way :
#include <filesystem>
#include <iostream>
#include <vector>
namespace fs = std::filesystem;
int main()
{
std::ios_base::sync_with_stdio(false);
for (const auto &entry : fs::recursive_directory_iterator(".")) {
if (entry.path().extension() == ".png") {
std::cout << entry.path().string() << std::endl;
}
}
return 0;
}
If you are on Windows, you can use the FindFirstFile together with FindNextFile API. You can use FindFileData.dwFileAttributes to check if a given path is a file or a directory. If it's a directory, you can recursively repeat the algorithm.
Here, I have put together some code that lists all the files on a Windows machine.
http://dreams-soft.com/projects/traverse-directory
File tree walk ftw is a recursive way to wall the whole directory tree in the path. More details are here.
NOTE : You can also use fts that can skip hidden files like . or .. or .bashrc
#include <ftw.h>
#include <stdio.h>
#include <sys/stat.h>
#include <string.h>
int list(const char *name, const struct stat *status, int type)
{
if (type == FTW_NS)
{
return 0;
}
if (type == FTW_F)
{
printf("0%3o\t%s\n", status->st_mode&0777, name);
}
if (type == FTW_D && strcmp(".", name) != 0)
{
printf("0%3o\t%s/\n", status->st_mode&0777, name);
}
return 0;
}
int main(int argc, char *argv[])
{
if(argc == 1)
{
ftw(".", list, 1);
}
else
{
ftw(argv[1], list, 1);
}
return 0;
}
output looks like following:
0755 ./Shivaji/
0644 ./Shivaji/20200516_204454.png
0644 ./Shivaji/20200527_160408.png
0644 ./Shivaji/20200527_160352.png
0644 ./Shivaji/20200520_174754.png
0644 ./Shivaji/20200520_180103.png
0755 ./Saif/
0644 ./Saif/Snapchat-1751229005.jpg
0644 ./Saif/Snapchat-1356123194.jpg
0644 ./Saif/Snapchat-613911286.jpg
0644 ./Saif/Snapchat-107742096.jpg
0755 ./Milind/
0644 ./Milind/IMG_1828.JPG
0644 ./Milind/IMG_1839.JPG
0644 ./Milind/IMG_1825.JPG
0644 ./Milind/IMG_1831.JPG
0644 ./Milind/IMG_1840.JPG
Let us say if you want to match a filename (example: searching for all the *.jpg, *.jpeg, *.png files.) for a specific needs, use fnmatch.
#include <ftw.h>
#include <stdio.h>
#include <sys/stat.h>
#include <iostream>
#include <fnmatch.h>
static const char *filters[] = {
"*.jpg", "*.jpeg", "*.png"
};
int list(const char *name, const struct stat *status, int type)
{
if (type == FTW_NS)
{
return 0;
}
if (type == FTW_F)
{
int i;
for (i = 0; i < sizeof(filters) / sizeof(filters[0]); i++) {
/* if the filename matches the filter, */
if (fnmatch(filters[i], name, FNM_CASEFOLD) == 0) {
printf("0%3o\t%s\n", status->st_mode&0777, name);
break;
}
}
}
if (type == FTW_D && strcmp(".", name) != 0)
{
//printf("0%3o\t%s/\n", status->st_mode&0777, name);
}
return 0;
}
int main(int argc, char *argv[])
{
if(argc == 1)
{
ftw(".", list, 1);
}
else
{
ftw(argv[1], list, 1);
}
return 0;
}
Answers of getting all file names recursively with C++11 for Windows and Linux(with experimental/filesystem):
For Windows:
#include <io.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <windows.h>
void getFiles_w(string path, vector<string>& files) {
intptr_t hFile = 0;
struct _finddata_t fileinfo;
string p;
if ((hFile = _findfirst(p.assign(path).append("\\*").c_str(), &fileinfo)) != -1) {
do {
if ((fileinfo.attrib & _A_SUBDIR)) {
if (strcmp(fileinfo.name, ".") != 0 && strcmp(fileinfo.name, "..") != 0)
getFiles(p.assign(path).append("/").append(fileinfo.name), files);
}
else {
files.push_back(p.assign(path).append("/").append(fileinfo.name));
}
} while (_findnext(hFile, &fileinfo) == 0);
}
}
For Linux:
#include <experimental/filesystem>
bool getFiles(std::experimental::filesystem::path path, vector<string>& filenames) {
namespace stdfs = std::experimental::filesystem;
// http://en.cppreference.com/w/cpp/experimental/fs/directory_iterator
const stdfs::directory_iterator end{} ;
for (stdfs::directory_iterator iter{path}; iter != end ; ++iter) {
// http://en.cppreference.com/w/cpp/experimental/fs/is_regular_file
if (!stdfs::is_regular_file(*iter)) { // comment out if all names (names of directories tc.) are required
if (getFiles(iter->path(), filenames))
return true;
}
else {
filenames.push_back(iter->path().string()) ;
cout << iter->path().string() << endl;
}
}
return false;
}
Just remember to link -lstdc++fs when you compile it with g++ in Linux.
Employee Visual C++ and WIN API:
bool Parser::queryDIR(string dir_name) {
vector<string> sameLayerFiles;
bool ret = false;
string dir = "";
//employee wide char
dir = dir_name + "\\*.*";;
//employee WIN File API
WIN32_FIND_DATA fd;
WIN32_FIND_DATA fd_dir;
HANDLE hFind = ::FindFirstFile(getWC(dir.c_str()), &fd);
HANDLE hFind_dir = ::FindFirstFile(getWC(dir.c_str()), &fd_dir);
string str_subdir;
string str_tmp;
//recursive call for diving into sub-directories
do {
if ((fd_dir.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ) {
//ignore trival file node
while(true) {
FindNextFile(hFind_dir, &fd_dir);
str_tmp = wc2str(fd_dir.cFileName);
if (str_tmp.compare(".") && str_tmp.compare("..")){
break;
}
}
if ((fd_dir.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ) {
str_subdir = wc2str(fd_dir.cFileName);
ret = queryDIR(dir_name + "\\" + str_subdir);
}
}
} while(::FindNextFile(hFind_dir, &fd_dir));
//iterate same layer files
do {
if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
str_tmp = wc2str(fd.cFileName);
string fname = dir_name + "\\" + str_tmp;
sameLayerFiles.push_back(fname);
}
} while(::FindNextFile(hFind, &fd));
for (std::vector<string>::iterator it=sameLayerFiles.begin(); it!=sameLayerFiles.end(); it++) {
std::cout << "iterated file:" << *it << "..." << std::endl;
//Doing something with every file here
}
return true;
}
Hope my code can help :)
And you can see more details and program screen-shots on My GitHub

Get process name on specified port [duplicate]

I need a C/C++ API that allows me to list the running processes on a Linux system, and list the files each process has open.
I do not want to end up reading the /proc/ file system directly.
Can anyone think of a way to do this?
http://procps.sourceforge.net/
http://procps.cvs.sourceforge.net/viewvc/procps/procps/proc/readproc.c?view=markup
Is the source of ps and other process tools. They do indeed use proc (indicating it is probably the conventional and best way). Their source is quite readable. The file
/procps-3.2.8/proc/readproc.c
May be useful. Also a useful suggestion as posted by ephemient is linking to the API provided by libproc, which should be available in your repo (or already installed I would say) but you will need the "-dev" variation for the headers and what-not.
Good Luck
If you do not want to read from '/proc. Then you can consider writing a Kernel module which will implement your own system call. And your system call should be written so that it can obtain the list of current processes, such as:
/* ProcessList.c
Robert Love Chapter 3
*/
#include < linux/kernel.h >
#include < linux/sched.h >
#include < linux/module.h >
int init_module(void) {
struct task_struct *task;
for_each_process(task) {
printk("%s [%d]\n",task->comm , task->pid);
}
return 0;
}
void cleanup_module(void) {
printk(KERN_INFO "Cleaning Up.\n");
}
The code above is taken from my article here at http://linuxgazette.net/133/saha.html.Once you have your own system call, you can call it from your user space program.
Here you go (C/C++):
You could have found it here:
http://ubuntuforums.org/showthread.php?t=657097
Essentially, what it does is loop through all numeric folders in /proc/<pid>, and then it does a readlink on /proc/<pid>/exe, or if you want the command-line-arguments cat /proc/<pid>/cmdline
The file-descriptors open by the process are in /proc/<pid>/fd/<descriptor>, and you get the file name by doing a readlink on each symlink, e.g. readlink /proc/<pid>/fd/<descriptor>. fd can be a device, such as /dev/null, a socket, or a file, and potentially more.
#include <unistd.h>
ssize_t readlink(const char *path, char *buf, size_t bufsiz);
On success, readlink() returns the number of bytes placed in buf.
On error, -1 is returned and errno is set to indicate the error.
This is, by the way, the same that readproc.c does (or at least did).
Of course, hopefully they did it without buffer overflow possiblity.
#ifndef __cplusplus
#define _GNU_SOURCE
#endif
#include <unistd.h>
#include <dirent.h>
#include <sys/types.h> // for opendir(), readdir(), closedir()
#include <sys/stat.h> // for stat()
#ifdef __cplusplus
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdarg>
#else
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#endif
#define PROC_DIRECTORY "/proc/"
#define CASE_SENSITIVE 1
#define CASE_INSENSITIVE 0
#define EXACT_MATCH 1
#define INEXACT_MATCH 0
int IsNumeric(const char* ccharptr_CharacterList)
{
for ( ; *ccharptr_CharacterList; ccharptr_CharacterList++)
if (*ccharptr_CharacterList < '0' || *ccharptr_CharacterList > '9')
return 0; // false
return 1; // true
}
int strcmp_Wrapper(const char *s1, const char *s2, int intCaseSensitive)
{
if (intCaseSensitive)
return !strcmp(s1, s2);
else
return !strcasecmp(s1, s2);
}
int strstr_Wrapper(const char* haystack, const char* needle, int intCaseSensitive)
{
if (intCaseSensitive)
return (int) strstr(haystack, needle);
else
return (int) strcasestr(haystack, needle);
}
#ifdef __cplusplus
pid_t GetPIDbyName(const char* cchrptr_ProcessName, int intCaseSensitiveness, int intExactMatch)
#else
pid_t GetPIDbyName_implements(const char* cchrptr_ProcessName, int intCaseSensitiveness, int intExactMatch)
#endif
{
char chrarry_CommandLinePath[100] ;
char chrarry_NameOfProcess[300] ;
char* chrptr_StringToCompare = NULL ;
pid_t pid_ProcessIdentifier = (pid_t) -1 ;
struct dirent* de_DirEntity = NULL ;
DIR* dir_proc = NULL ;
int (*CompareFunction) (const char*, const char*, int) ;
if (intExactMatch)
CompareFunction = &strcmp_Wrapper;
else
CompareFunction = &strstr_Wrapper;
dir_proc = opendir(PROC_DIRECTORY) ;
if (dir_proc == NULL)
{
perror("Couldn't open the " PROC_DIRECTORY " directory") ;
return (pid_t) -2 ;
}
// Loop while not NULL
while ( (de_DirEntity = readdir(dir_proc)) )
{
if (de_DirEntity->d_type == DT_DIR)
{
if (IsNumeric(de_DirEntity->d_name))
{
strcpy(chrarry_CommandLinePath, PROC_DIRECTORY) ;
strcat(chrarry_CommandLinePath, de_DirEntity->d_name) ;
strcat(chrarry_CommandLinePath, "/cmdline") ;
FILE* fd_CmdLineFile = fopen (chrarry_CommandLinePath, "rt") ; // open the file for reading text
if (fd_CmdLineFile)
{
fscanf(fd_CmdLineFile, "%s", chrarry_NameOfProcess) ; // read from /proc/<NR>/cmdline
fclose(fd_CmdLineFile); // close the file prior to exiting the routine
if (strrchr(chrarry_NameOfProcess, '/'))
chrptr_StringToCompare = strrchr(chrarry_NameOfProcess, '/') +1 ;
else
chrptr_StringToCompare = chrarry_NameOfProcess ;
//printf("Process name: %s\n", chrarry_NameOfProcess);
//printf("Pure Process name: %s\n", chrptr_StringToCompare );
if ( CompareFunction(chrptr_StringToCompare, cchrptr_ProcessName, intCaseSensitiveness) )
{
pid_ProcessIdentifier = (pid_t) atoi(de_DirEntity->d_name) ;
closedir(dir_proc) ;
return pid_ProcessIdentifier ;
}
}
}
}
}
closedir(dir_proc) ;
return pid_ProcessIdentifier ;
}
#ifdef __cplusplus
pid_t GetPIDbyName(const char* cchrptr_ProcessName)
{
return GetPIDbyName(cchrptr_ProcessName, CASE_INSENSITIVE, EXACT_MATCH) ;
}
#else
// C cannot overload functions - fixed
pid_t GetPIDbyName_Wrapper(const char* cchrptr_ProcessName, ... )
{
int intTempArgument ;
int intInputArguments[2] ;
// intInputArguments[0] = 0 ;
// intInputArguments[1] = 0 ;
memset(intInputArguments, 0, sizeof(intInputArguments) ) ;
int intInputIndex ;
va_list argptr;
va_start( argptr, cchrptr_ProcessName );
for (intInputIndex = 0; (intTempArgument = va_arg( argptr, int )) != 15; ++intInputIndex)
{
intInputArguments[intInputIndex] = intTempArgument ;
}
va_end( argptr );
return GetPIDbyName_implements(cchrptr_ProcessName, intInputArguments[0], intInputArguments[1]);
}
#define GetPIDbyName(ProcessName,...) GetPIDbyName_Wrapper(ProcessName, ##__VA_ARGS__, (int) 15)
#endif
int main()
{
pid_t pid = GetPIDbyName("bash") ; // If -1 = not found, if -2 = proc fs access error
printf("PID %d\n", pid);
return EXIT_SUCCESS ;
}
If you don't do it, then I guess whatever API you will use will end up reading the /proc filesystem. Here are some examples of program doing this:
qps
htop
procps
But unfortunately, that does not constitute an API.
PS and every other tool(EXCEPT for Kernel Modules) read from /proc. /proc is a special filesystem created on the fly by the kernel so that user mode processes can read data that will otherwise only be available for the kernel.
The recommended way is therefore, reading from /proc.
You can quickly intuitively look at the /proc filesystem to see how its structured.
For every process there is a /proc/pid where pid is the process id number. Inside this folder there are several files which include different data about the current process.
If you run
strace ps -aux
you will see how the program ps reads this data from /proc.
The only way to do this without reading /proc would be to call "ps aux", go through every line, read the second column (the PID) and call lsof -p [PID] with it.
...I'd suggest reading /proc ;)
There's a library libprocps from the procps-ng project. On Ubuntu 13.04, if you do strace ps, then you can see that ps uses libprocps.
Reading proc is not too bad. I can't show you in C++, but the following D code should point you in the right direction:
import std.stdio;
import std.string;
import std.file;
import std.regexp;
import std.c.linux.linux;
alias std.string.split explode;
string srex = "^/proc/[0-9]+$";
string trex = "State:[ \t][SR]";
RegExp rex;
RegExp rext;
string[] scanPidDirs(string target)
{
string[] result;
bool callback(DirEntry* de)
{
if (de.isdir)
{
if (rex.find(de.name) >= 0)
{
string[] a = explode(de.name, "/");
string pid = a[a.length-1];
string x = cast(string) std.file.read(de.name ~ "/status");
int n = rext.find(x);
if (n >= 0)
{
x = cast(string) std.file.read(de.name ~ "/cmdline");
// This is null terminated
if (x.length) x.length = x.length-1;
a = explode(x, "/");
if (a.length)
x = a[a.length-1];
else
x = "";
if (x == target)
{
result ~= pid ~ "/" ~x;
}
}
}
}
return true;
}
listdir("/proc", &callback);
return result.dup;
}
void main(string[] args)
{
rex= new RegExp(srex);
rext= new RegExp(trex);
string[] a = scanPidDirs(args[1]);
if (!a.length)
{
writefln("Not found");
return;
}
writefln("%d matching processes", a.length);
foreach (s; a)
{
string[] p = explode(s, "/");
int pid = atoi(p[0]);
writef("Stop %s (%d)? ", s, pid);
string r = readln();
if (r == "Y\n" || r == "y\n")
kill(pid, SIGUSR1);
}
}
Easy way to fin pid of any process by name
pid_t GetPIDbyName(char* ps_name)
{
FILE *fp;
char *cmd=(char*)calloc(1,200);
sprintf(cmd,"pidof %s",ps_name);
fp=popen(cmd,"r");
fread(cmd,1,200,fp);
fclose(fp);
return atoi(cmd);
}

Printing all the directories using c++

This program is printing the directories at the root level
Directory_1
Directory_2
but I want to be able to print the directories within them too
Directory_1
Directory_1_2
Directory_1_3
Directory_2
Directory 2_1
Directory_2_1_1
Directory_4
I am trying to do it recursively but I am finding it hard to pass the Directory_1 as a root so it gets evaluated.. What am i missing?
Here is my output
..
.
Directory_1
Directory_2
Failed to open directory: No such file or directory
Code
#include <dirent.h>
#include <errno.h>
#include <stdio.h>
#include <sys/stat.h>
char *arg_temp;
int printDepthFirst(char *arg_tmp);
int main(int argc, char *argv[]) {
if (argc != 2) {
fprintf(stderr, "Usage: %s directory_name\n", argv[0]);
return 1;
}
arg_temp = argv[1];
printDepthFirst(arg_temp);
}
int printDepthFirst(char *arg_tmp)
{
struct dirent *direntp;
DIR *dirp;
if ((dirp = opendir(arg_tmp)) == NULL) {
perror ("Failed to open directory");
return 1;
}
while ((direntp = readdir(dirp)) != NULL)
{
printf("%s\n", direntp->d_name);
arg_tmp = direntp->d_name;
}
printDepthFirst(arg_tmp);
while ((closedir(dirp) == -1) && (errno == EINTR)) ;
return 0;
}
Now, I know some people get irritated when asking questions that they think I am expecting them to code this, you dont need to, if you can tell me theoretically what i need to do.. I will research it although if its a small programmatically fix and you can post that I would really appreaciate it.. but if not.. I would also love to hear about what needs to be done in words..
Thank you
Well this should help:
#define _XOPEN_SOURCE 500
#include <ftw.h>
#include <stdio.h>
static int display_info(const char *fpath, const struct stat *sb,
int tflag, struct FTW *ftwbuf)
{
switch(tflag)
{
case FTW_D:
case FTW_DP: puts(fpath); break;
}
return 0; /* To tell nftw() to continue */
}
int main(int argc, char *argv[])
{
if (argc != 2) {
fprintf(stderr, "Usage: %s directory_name\n", argv[0]);
return 1;
}
int flags = FTW_DEPTH | FTW_MOUNT | FTW_PHYS;
if (nftw(argv[1], display_info, 20, flags) == -1)
{
perror("nftw");
return 255;
}
return 0;
}
Have a look at what fields struct dirent contains.
The string dirent::d_name is a name of a directory, not it's full path. So, if your directory "C:\Alpha" contains directory "C:\Alpha\Beta", d_name would only contatin "Beta", not "C:\Alpha\Beta". You will have to assemble the full path yourself - appending slash/backslash to your arg_tmp and then appending new directory name, like this:
while ((direntp = readdir (dirp)) != NULL)
{
char *dirname = direntp->d_name;
// Only work with directories and avoid recursion on "." and "..":
if (direntp->d_type != DT_DIR || !strcmp (dirname, ".") || !strcmp (dirname, "..")) continue;
// Assemble full directory path:
char current [strlen (arg_tmp) + 2 + strlen (dirname)];
strcpy (current, arg_tmp);
strcat (current, "\\"); // Replace "\\" with "/" on *nix systems
strcat (current, dirname);
// Show it and continue:
printf ("%s\n", current);
printDepthFirst (current);
}
Also, you should call recursively inside the loop, not outside.
Inside your while loop inside printDepthFirst you might need something like:
if(direntp->d_type == DT_DIR)
printDepthFirst(directp->d_name);
You might perhaps have to worry about .. directories too.
Alternatively, I've found boost::filesystem to work quite well.

C++ how to check if folder is empty / list existing files [duplicate]

How do you iterate through every file/directory recursively in standard C++?
From C++17 onward, the <filesystem> header, and range-for, you can simply do this:
#include <filesystem>
using recursive_directory_iterator = std::filesystem::recursive_directory_iterator;
...
for (const auto& dirEntry : recursive_directory_iterator(myPath))
std::cout << dirEntry << std::endl;
As of C++17, std::filesystem is part of the standard library and can be found in the <filesystem> header (no longer "experimental").
In standard C++, technically there is no way to do this since standard C++ has no conception of directories. If you want to expand your net a little bit, you might like to look at using Boost.FileSystem. This has been accepted for inclusion in TR2, so this gives you the best chance of keeping your implementation as close as possible to the standard.
An example, taken straight from the website:
bool find_file( const path & dir_path, // in this directory,
const std::string & file_name, // search for this name,
path & path_found ) // placing path here if found
{
if ( !exists( dir_path ) ) return false;
directory_iterator end_itr; // default construction yields past-the-end
for ( directory_iterator itr( dir_path );
itr != end_itr;
++itr )
{
if ( is_directory(itr->status()) )
{
if ( find_file( itr->path(), file_name, path_found ) ) return true;
}
else if ( itr->leaf() == file_name ) // see below
{
path_found = itr->path();
return true;
}
}
return false;
}
If using the Win32 API you can use the FindFirstFile and FindNextFile functions.
http://msdn.microsoft.com/en-us/library/aa365200(VS.85).aspx
For recursive traversal of directories you must inspect each WIN32_FIND_DATA.dwFileAttributes to check if the FILE_ATTRIBUTE_DIRECTORY bit is set. If the bit is set then you can recursively call the function with that directory. Alternatively you can use a stack for providing the same effect of a recursive call but avoiding stack overflow for very long path trees.
#include <windows.h>
#include <string>
#include <vector>
#include <stack>
#include <iostream>
using namespace std;
bool ListFiles(wstring path, wstring mask, vector<wstring>& files) {
HANDLE hFind = INVALID_HANDLE_VALUE;
WIN32_FIND_DATA ffd;
wstring spec;
stack<wstring> directories;
directories.push(path);
files.clear();
while (!directories.empty()) {
path = directories.top();
spec = path + L"\\" + mask;
directories.pop();
hFind = FindFirstFile(spec.c_str(), &ffd);
if (hFind == INVALID_HANDLE_VALUE) {
return false;
}
do {
if (wcscmp(ffd.cFileName, L".") != 0 &&
wcscmp(ffd.cFileName, L"..") != 0) {
if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
directories.push(path + L"\\" + ffd.cFileName);
}
else {
files.push_back(path + L"\\" + ffd.cFileName);
}
}
} while (FindNextFile(hFind, &ffd) != 0);
if (GetLastError() != ERROR_NO_MORE_FILES) {
FindClose(hFind);
return false;
}
FindClose(hFind);
hFind = INVALID_HANDLE_VALUE;
}
return true;
}
int main(int argc, char* argv[])
{
vector<wstring> files;
if (ListFiles(L"F:\\cvsrepos", L"*", files)) {
for (vector<wstring>::iterator it = files.begin();
it != files.end();
++it) {
wcout << it->c_str() << endl;
}
}
return 0;
}
You can make it even simpler with the new C++11 range based for and Boost:
#include <boost/filesystem.hpp>
using namespace boost::filesystem;
struct recursive_directory_range
{
typedef recursive_directory_iterator iterator;
recursive_directory_range(path p) : p_(p) {}
iterator begin() { return recursive_directory_iterator(p_); }
iterator end() { return recursive_directory_iterator(); }
path p_;
};
for (auto it : recursive_directory_range(dir_path))
{
std::cout << it << std::endl;
}
A fast solution is using C's Dirent.h library.
Working code fragment from Wikipedia:
#include <stdio.h>
#include <dirent.h>
int listdir(const char *path) {
struct dirent *entry;
DIR *dp;
dp = opendir(path);
if (dp == NULL) {
perror("opendir: Path does not exist or could not be read.");
return -1;
}
while ((entry = readdir(dp)))
puts(entry->d_name);
closedir(dp);
return 0;
}
You can use std::filesystem::recursive_directory_iterator. But beware, this includes symbolic (soft) links. If you want to avoid them you can use is_symlink. Example usage:
size_t directory_size(const std::filesystem::path& directory)
{
size_t size{ 0 };
for (const auto& entry : std::filesystem::recursive_directory_iterator(directory))
{
if (entry.is_regular_file() && !entry.is_symlink())
{
size += entry.file_size();
}
}
return size;
}
In addition to the above mentioned boost::filesystem you may want to examine wxWidgets::wxDir and Qt::QDir.
Both wxWidgets and Qt are open source, cross platform C++ frameworks.
wxDir provides a flexible way to traverse files recursively using Traverse() or a simpler GetAllFiles() function. As well you can implement the traversal with GetFirst() and GetNext() functions (I assume that Traverse() and GetAllFiles() are wrappers that eventually use GetFirst() and GetNext() functions).
QDir provides access to directory structures and their contents. There are several ways to traverse directories with QDir. You can iterate over the directory contents (including sub-directories) with QDirIterator that was instantiated with QDirIterator::Subdirectories flag. Another way is to use QDir's GetEntryList() function and implement a recursive traversal.
Here is sample code (taken from here # Example 8-5) that shows how to iterate over all sub directories.
#include <qapplication.h>
#include <qdir.h>
#include <iostream>
int main( int argc, char **argv )
{
QApplication a( argc, argv );
QDir currentDir = QDir::current();
currentDir.setFilter( QDir::Dirs );
QStringList entries = currentDir.entryList();
for( QStringList::ConstIterator entry=entries.begin(); entry!=entries.end(); ++entry)
{
std::cout << *entry << std::endl;
}
return 0;
}
Boost::filesystem provides recursive_directory_iterator, which is quite convenient for this task:
#include "boost/filesystem.hpp"
#include <iostream>
using namespace boost::filesystem;
recursive_directory_iterator end;
for (recursive_directory_iterator it("./"); it != end; ++it) {
std::cout << *it << std::endl;
}
You can use ftw(3) or nftw(3) to walk a filesystem hierarchy in C or C++ on POSIX systems.
We are in 2019. We have filesystem standard library in C++. The Filesystem library provides facilities for performing operations on file systems and their components, such as paths, regular files, and directories.
There is an important note on this link if you are considering portability issues. It says:
The filesystem library facilities may be unavailable if a hierarchical file system is not accessible to the implementation, or if it does not provide the necessary capabilities. Some features may not be available if they are not supported by the underlying file system (e.g. the FAT filesystem lacks symbolic links and forbids multiple hardlinks). In those cases, errors must be reported.
The filesystem library was originally developed as boost.filesystem, was published as the technical specification ISO/IEC TS 18822:2015, and finally merged to ISO C++ as of C++17. The boost implementation is currently available on more compilers and platforms than the C++17 library.
#adi-shavit has answered this question when it was part of std::experimental and he has updated this answer in 2017. I want to give more details about the library and show more detailed example.
std::filesystem::recursive_directory_iterator is an LegacyInputIterator that iterates over the directory_entry elements of a directory, and, recursively, over the entries of all subdirectories. The iteration order is unspecified, except that each directory entry is visited only once.
If you don't want to recursively iterate over the entries of subdirectories, then directory_iterator should be used.
Both iterators returns an object of directory_entry. directory_entry has various useful member functions like is_regular_file, is_directory, is_socket, is_symlink etc. The path() member function returns an object of std::filesystem::path and it can be used to get file extension, filename, root name.
Consider the example below. I have been using Ubuntu and compiled it over the terminal using
g++ example.cpp --std=c++17 -lstdc++fs -Wall
#include <iostream>
#include <string>
#include <filesystem>
void listFiles(std::string path)
{
for (auto& dirEntry: std::filesystem::recursive_directory_iterator(path)) {
if (!dirEntry.is_regular_file()) {
std::cout << "Directory: " << dirEntry.path() << std::endl;
continue;
}
std::filesystem::path file = dirEntry.path();
std::cout << "Filename: " << file.filename() << " extension: " << file.extension() << std::endl;
}
}
int main()
{
listFiles("./");
return 0;
}
You would probably be best with either boost or c++14's experimental filesystem stuff. IF you are parsing an internal directory (ie. used for your program to store data after the program was closed), then make an index file that has an index of the file contents. By the way, you probably would need to use boost in the future, so if you don't have it installed, install it! Second of all, you could use a conditional compilation, e.g.:
#ifdef WINDOWS //define WINDOWS in your code to compile for windows
#endif
The code for each case is taken from https://stackoverflow.com/a/67336/7077165
#ifdef POSIX //unix, linux, etc.
#include <stdio.h>
#include <dirent.h>
int listdir(const char *path) {
struct dirent *entry;
DIR *dp;
dp = opendir(path);
if (dp == NULL) {
perror("opendir: Path does not exist or could not be read.");
return -1;
}
while ((entry = readdir(dp)))
puts(entry->d_name);
closedir(dp);
return 0;
}
#endif
#ifdef WINDOWS
#include <windows.h>
#include <string>
#include <vector>
#include <stack>
#include <iostream>
using namespace std;
bool ListFiles(wstring path, wstring mask, vector<wstring>& files) {
HANDLE hFind = INVALID_HANDLE_VALUE;
WIN32_FIND_DATA ffd;
wstring spec;
stack<wstring> directories;
directories.push(path);
files.clear();
while (!directories.empty()) {
path = directories.top();
spec = path + L"\\" + mask;
directories.pop();
hFind = FindFirstFile(spec.c_str(), &ffd);
if (hFind == INVALID_HANDLE_VALUE) {
return false;
}
do {
if (wcscmp(ffd.cFileName, L".") != 0 &&
wcscmp(ffd.cFileName, L"..") != 0) {
if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
directories.push(path + L"\\" + ffd.cFileName);
}
else {
files.push_back(path + L"\\" + ffd.cFileName);
}
}
} while (FindNextFile(hFind, &ffd) != 0);
if (GetLastError() != ERROR_NO_MORE_FILES) {
FindClose(hFind);
return false;
}
FindClose(hFind);
hFind = INVALID_HANDLE_VALUE;
}
return true;
}
#endif
//so on and so forth.
You don't. The C++ standard has no concept of directories. It is up to the implementation to turn a string into a file handle. The contents of that string and what it maps to is OS dependent. Keep in mind that C++ can be used to write that OS, so it gets used at a level where asking how to iterate through a directory is not yet defined (because you are writing the directory management code).
Look at your OS API documentation for how to do this. If you need to be portable, you will have to have a bunch of #ifdefs for various OSes.
You need to call OS-specific functions for filesystem traversal, like open() and readdir(). The C standard does not specify any filesystem-related functions.
You don't. Standard C++ doesn't expose to concept of a directory. Specifically it doesn't give any way to list all the files in a directory.
A horrible hack would be to use system() calls and to parse the results. The most reasonable solution would be to use some kind of cross-platform library such as Qt or even POSIX.
On C++17 you can by this way :
#include <filesystem>
#include <iostream>
#include <vector>
namespace fs = std::filesystem;
int main()
{
std::ios_base::sync_with_stdio(false);
for (const auto &entry : fs::recursive_directory_iterator(".")) {
if (entry.path().extension() == ".png") {
std::cout << entry.path().string() << std::endl;
}
}
return 0;
}
If you are on Windows, you can use the FindFirstFile together with FindNextFile API. You can use FindFileData.dwFileAttributes to check if a given path is a file or a directory. If it's a directory, you can recursively repeat the algorithm.
Here, I have put together some code that lists all the files on a Windows machine.
http://dreams-soft.com/projects/traverse-directory
File tree walk ftw is a recursive way to wall the whole directory tree in the path. More details are here.
NOTE : You can also use fts that can skip hidden files like . or .. or .bashrc
#include <ftw.h>
#include <stdio.h>
#include <sys/stat.h>
#include <string.h>
int list(const char *name, const struct stat *status, int type)
{
if (type == FTW_NS)
{
return 0;
}
if (type == FTW_F)
{
printf("0%3o\t%s\n", status->st_mode&0777, name);
}
if (type == FTW_D && strcmp(".", name) != 0)
{
printf("0%3o\t%s/\n", status->st_mode&0777, name);
}
return 0;
}
int main(int argc, char *argv[])
{
if(argc == 1)
{
ftw(".", list, 1);
}
else
{
ftw(argv[1], list, 1);
}
return 0;
}
output looks like following:
0755 ./Shivaji/
0644 ./Shivaji/20200516_204454.png
0644 ./Shivaji/20200527_160408.png
0644 ./Shivaji/20200527_160352.png
0644 ./Shivaji/20200520_174754.png
0644 ./Shivaji/20200520_180103.png
0755 ./Saif/
0644 ./Saif/Snapchat-1751229005.jpg
0644 ./Saif/Snapchat-1356123194.jpg
0644 ./Saif/Snapchat-613911286.jpg
0644 ./Saif/Snapchat-107742096.jpg
0755 ./Milind/
0644 ./Milind/IMG_1828.JPG
0644 ./Milind/IMG_1839.JPG
0644 ./Milind/IMG_1825.JPG
0644 ./Milind/IMG_1831.JPG
0644 ./Milind/IMG_1840.JPG
Let us say if you want to match a filename (example: searching for all the *.jpg, *.jpeg, *.png files.) for a specific needs, use fnmatch.
#include <ftw.h>
#include <stdio.h>
#include <sys/stat.h>
#include <iostream>
#include <fnmatch.h>
static const char *filters[] = {
"*.jpg", "*.jpeg", "*.png"
};
int list(const char *name, const struct stat *status, int type)
{
if (type == FTW_NS)
{
return 0;
}
if (type == FTW_F)
{
int i;
for (i = 0; i < sizeof(filters) / sizeof(filters[0]); i++) {
/* if the filename matches the filter, */
if (fnmatch(filters[i], name, FNM_CASEFOLD) == 0) {
printf("0%3o\t%s\n", status->st_mode&0777, name);
break;
}
}
}
if (type == FTW_D && strcmp(".", name) != 0)
{
//printf("0%3o\t%s/\n", status->st_mode&0777, name);
}
return 0;
}
int main(int argc, char *argv[])
{
if(argc == 1)
{
ftw(".", list, 1);
}
else
{
ftw(argv[1], list, 1);
}
return 0;
}
Answers of getting all file names recursively with C++11 for Windows and Linux(with experimental/filesystem):
For Windows:
#include <io.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <windows.h>
void getFiles_w(string path, vector<string>& files) {
intptr_t hFile = 0;
struct _finddata_t fileinfo;
string p;
if ((hFile = _findfirst(p.assign(path).append("\\*").c_str(), &fileinfo)) != -1) {
do {
if ((fileinfo.attrib & _A_SUBDIR)) {
if (strcmp(fileinfo.name, ".") != 0 && strcmp(fileinfo.name, "..") != 0)
getFiles(p.assign(path).append("/").append(fileinfo.name), files);
}
else {
files.push_back(p.assign(path).append("/").append(fileinfo.name));
}
} while (_findnext(hFile, &fileinfo) == 0);
}
}
For Linux:
#include <experimental/filesystem>
bool getFiles(std::experimental::filesystem::path path, vector<string>& filenames) {
namespace stdfs = std::experimental::filesystem;
// http://en.cppreference.com/w/cpp/experimental/fs/directory_iterator
const stdfs::directory_iterator end{} ;
for (stdfs::directory_iterator iter{path}; iter != end ; ++iter) {
// http://en.cppreference.com/w/cpp/experimental/fs/is_regular_file
if (!stdfs::is_regular_file(*iter)) { // comment out if all names (names of directories tc.) are required
if (getFiles(iter->path(), filenames))
return true;
}
else {
filenames.push_back(iter->path().string()) ;
cout << iter->path().string() << endl;
}
}
return false;
}
Just remember to link -lstdc++fs when you compile it with g++ in Linux.
Employee Visual C++ and WIN API:
bool Parser::queryDIR(string dir_name) {
vector<string> sameLayerFiles;
bool ret = false;
string dir = "";
//employee wide char
dir = dir_name + "\\*.*";;
//employee WIN File API
WIN32_FIND_DATA fd;
WIN32_FIND_DATA fd_dir;
HANDLE hFind = ::FindFirstFile(getWC(dir.c_str()), &fd);
HANDLE hFind_dir = ::FindFirstFile(getWC(dir.c_str()), &fd_dir);
string str_subdir;
string str_tmp;
//recursive call for diving into sub-directories
do {
if ((fd_dir.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ) {
//ignore trival file node
while(true) {
FindNextFile(hFind_dir, &fd_dir);
str_tmp = wc2str(fd_dir.cFileName);
if (str_tmp.compare(".") && str_tmp.compare("..")){
break;
}
}
if ((fd_dir.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ) {
str_subdir = wc2str(fd_dir.cFileName);
ret = queryDIR(dir_name + "\\" + str_subdir);
}
}
} while(::FindNextFile(hFind_dir, &fd_dir));
//iterate same layer files
do {
if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
str_tmp = wc2str(fd.cFileName);
string fname = dir_name + "\\" + str_tmp;
sameLayerFiles.push_back(fname);
}
} while(::FindNextFile(hFind, &fd));
for (std::vector<string>::iterator it=sameLayerFiles.begin(); it!=sameLayerFiles.end(); it++) {
std::cout << "iterated file:" << *it << "..." << std::endl;
//Doing something with every file here
}
return true;
}
Hope my code can help :)
And you can see more details and program screen-shots on My GitHub

How do you iterate through every file/directory recursively in standard C++?

How do you iterate through every file/directory recursively in standard C++?
From C++17 onward, the <filesystem> header, and range-for, you can simply do this:
#include <filesystem>
using recursive_directory_iterator = std::filesystem::recursive_directory_iterator;
...
for (const auto& dirEntry : recursive_directory_iterator(myPath))
std::cout << dirEntry << std::endl;
As of C++17, std::filesystem is part of the standard library and can be found in the <filesystem> header (no longer "experimental").
In standard C++, technically there is no way to do this since standard C++ has no conception of directories. If you want to expand your net a little bit, you might like to look at using Boost.FileSystem. This has been accepted for inclusion in TR2, so this gives you the best chance of keeping your implementation as close as possible to the standard.
An example, taken straight from the website:
bool find_file( const path & dir_path, // in this directory,
const std::string & file_name, // search for this name,
path & path_found ) // placing path here if found
{
if ( !exists( dir_path ) ) return false;
directory_iterator end_itr; // default construction yields past-the-end
for ( directory_iterator itr( dir_path );
itr != end_itr;
++itr )
{
if ( is_directory(itr->status()) )
{
if ( find_file( itr->path(), file_name, path_found ) ) return true;
}
else if ( itr->leaf() == file_name ) // see below
{
path_found = itr->path();
return true;
}
}
return false;
}
If using the Win32 API you can use the FindFirstFile and FindNextFile functions.
http://msdn.microsoft.com/en-us/library/aa365200(VS.85).aspx
For recursive traversal of directories you must inspect each WIN32_FIND_DATA.dwFileAttributes to check if the FILE_ATTRIBUTE_DIRECTORY bit is set. If the bit is set then you can recursively call the function with that directory. Alternatively you can use a stack for providing the same effect of a recursive call but avoiding stack overflow for very long path trees.
#include <windows.h>
#include <string>
#include <vector>
#include <stack>
#include <iostream>
using namespace std;
bool ListFiles(wstring path, wstring mask, vector<wstring>& files) {
HANDLE hFind = INVALID_HANDLE_VALUE;
WIN32_FIND_DATA ffd;
wstring spec;
stack<wstring> directories;
directories.push(path);
files.clear();
while (!directories.empty()) {
path = directories.top();
spec = path + L"\\" + mask;
directories.pop();
hFind = FindFirstFile(spec.c_str(), &ffd);
if (hFind == INVALID_HANDLE_VALUE) {
return false;
}
do {
if (wcscmp(ffd.cFileName, L".") != 0 &&
wcscmp(ffd.cFileName, L"..") != 0) {
if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
directories.push(path + L"\\" + ffd.cFileName);
}
else {
files.push_back(path + L"\\" + ffd.cFileName);
}
}
} while (FindNextFile(hFind, &ffd) != 0);
if (GetLastError() != ERROR_NO_MORE_FILES) {
FindClose(hFind);
return false;
}
FindClose(hFind);
hFind = INVALID_HANDLE_VALUE;
}
return true;
}
int main(int argc, char* argv[])
{
vector<wstring> files;
if (ListFiles(L"F:\\cvsrepos", L"*", files)) {
for (vector<wstring>::iterator it = files.begin();
it != files.end();
++it) {
wcout << it->c_str() << endl;
}
}
return 0;
}
You can make it even simpler with the new C++11 range based for and Boost:
#include <boost/filesystem.hpp>
using namespace boost::filesystem;
struct recursive_directory_range
{
typedef recursive_directory_iterator iterator;
recursive_directory_range(path p) : p_(p) {}
iterator begin() { return recursive_directory_iterator(p_); }
iterator end() { return recursive_directory_iterator(); }
path p_;
};
for (auto it : recursive_directory_range(dir_path))
{
std::cout << it << std::endl;
}
A fast solution is using C's Dirent.h library.
Working code fragment from Wikipedia:
#include <stdio.h>
#include <dirent.h>
int listdir(const char *path) {
struct dirent *entry;
DIR *dp;
dp = opendir(path);
if (dp == NULL) {
perror("opendir: Path does not exist or could not be read.");
return -1;
}
while ((entry = readdir(dp)))
puts(entry->d_name);
closedir(dp);
return 0;
}
You can use std::filesystem::recursive_directory_iterator. But beware, this includes symbolic (soft) links. If you want to avoid them you can use is_symlink. Example usage:
size_t directory_size(const std::filesystem::path& directory)
{
size_t size{ 0 };
for (const auto& entry : std::filesystem::recursive_directory_iterator(directory))
{
if (entry.is_regular_file() && !entry.is_symlink())
{
size += entry.file_size();
}
}
return size;
}
In addition to the above mentioned boost::filesystem you may want to examine wxWidgets::wxDir and Qt::QDir.
Both wxWidgets and Qt are open source, cross platform C++ frameworks.
wxDir provides a flexible way to traverse files recursively using Traverse() or a simpler GetAllFiles() function. As well you can implement the traversal with GetFirst() and GetNext() functions (I assume that Traverse() and GetAllFiles() are wrappers that eventually use GetFirst() and GetNext() functions).
QDir provides access to directory structures and their contents. There are several ways to traverse directories with QDir. You can iterate over the directory contents (including sub-directories) with QDirIterator that was instantiated with QDirIterator::Subdirectories flag. Another way is to use QDir's GetEntryList() function and implement a recursive traversal.
Here is sample code (taken from here # Example 8-5) that shows how to iterate over all sub directories.
#include <qapplication.h>
#include <qdir.h>
#include <iostream>
int main( int argc, char **argv )
{
QApplication a( argc, argv );
QDir currentDir = QDir::current();
currentDir.setFilter( QDir::Dirs );
QStringList entries = currentDir.entryList();
for( QStringList::ConstIterator entry=entries.begin(); entry!=entries.end(); ++entry)
{
std::cout << *entry << std::endl;
}
return 0;
}
Boost::filesystem provides recursive_directory_iterator, which is quite convenient for this task:
#include "boost/filesystem.hpp"
#include <iostream>
using namespace boost::filesystem;
recursive_directory_iterator end;
for (recursive_directory_iterator it("./"); it != end; ++it) {
std::cout << *it << std::endl;
}
You can use ftw(3) or nftw(3) to walk a filesystem hierarchy in C or C++ on POSIX systems.
We are in 2019. We have filesystem standard library in C++. The Filesystem library provides facilities for performing operations on file systems and their components, such as paths, regular files, and directories.
There is an important note on this link if you are considering portability issues. It says:
The filesystem library facilities may be unavailable if a hierarchical file system is not accessible to the implementation, or if it does not provide the necessary capabilities. Some features may not be available if they are not supported by the underlying file system (e.g. the FAT filesystem lacks symbolic links and forbids multiple hardlinks). In those cases, errors must be reported.
The filesystem library was originally developed as boost.filesystem, was published as the technical specification ISO/IEC TS 18822:2015, and finally merged to ISO C++ as of C++17. The boost implementation is currently available on more compilers and platforms than the C++17 library.
#adi-shavit has answered this question when it was part of std::experimental and he has updated this answer in 2017. I want to give more details about the library and show more detailed example.
std::filesystem::recursive_directory_iterator is an LegacyInputIterator that iterates over the directory_entry elements of a directory, and, recursively, over the entries of all subdirectories. The iteration order is unspecified, except that each directory entry is visited only once.
If you don't want to recursively iterate over the entries of subdirectories, then directory_iterator should be used.
Both iterators returns an object of directory_entry. directory_entry has various useful member functions like is_regular_file, is_directory, is_socket, is_symlink etc. The path() member function returns an object of std::filesystem::path and it can be used to get file extension, filename, root name.
Consider the example below. I have been using Ubuntu and compiled it over the terminal using
g++ example.cpp --std=c++17 -lstdc++fs -Wall
#include <iostream>
#include <string>
#include <filesystem>
void listFiles(std::string path)
{
for (auto& dirEntry: std::filesystem::recursive_directory_iterator(path)) {
if (!dirEntry.is_regular_file()) {
std::cout << "Directory: " << dirEntry.path() << std::endl;
continue;
}
std::filesystem::path file = dirEntry.path();
std::cout << "Filename: " << file.filename() << " extension: " << file.extension() << std::endl;
}
}
int main()
{
listFiles("./");
return 0;
}
You would probably be best with either boost or c++14's experimental filesystem stuff. IF you are parsing an internal directory (ie. used for your program to store data after the program was closed), then make an index file that has an index of the file contents. By the way, you probably would need to use boost in the future, so if you don't have it installed, install it! Second of all, you could use a conditional compilation, e.g.:
#ifdef WINDOWS //define WINDOWS in your code to compile for windows
#endif
The code for each case is taken from https://stackoverflow.com/a/67336/7077165
#ifdef POSIX //unix, linux, etc.
#include <stdio.h>
#include <dirent.h>
int listdir(const char *path) {
struct dirent *entry;
DIR *dp;
dp = opendir(path);
if (dp == NULL) {
perror("opendir: Path does not exist or could not be read.");
return -1;
}
while ((entry = readdir(dp)))
puts(entry->d_name);
closedir(dp);
return 0;
}
#endif
#ifdef WINDOWS
#include <windows.h>
#include <string>
#include <vector>
#include <stack>
#include <iostream>
using namespace std;
bool ListFiles(wstring path, wstring mask, vector<wstring>& files) {
HANDLE hFind = INVALID_HANDLE_VALUE;
WIN32_FIND_DATA ffd;
wstring spec;
stack<wstring> directories;
directories.push(path);
files.clear();
while (!directories.empty()) {
path = directories.top();
spec = path + L"\\" + mask;
directories.pop();
hFind = FindFirstFile(spec.c_str(), &ffd);
if (hFind == INVALID_HANDLE_VALUE) {
return false;
}
do {
if (wcscmp(ffd.cFileName, L".") != 0 &&
wcscmp(ffd.cFileName, L"..") != 0) {
if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
directories.push(path + L"\\" + ffd.cFileName);
}
else {
files.push_back(path + L"\\" + ffd.cFileName);
}
}
} while (FindNextFile(hFind, &ffd) != 0);
if (GetLastError() != ERROR_NO_MORE_FILES) {
FindClose(hFind);
return false;
}
FindClose(hFind);
hFind = INVALID_HANDLE_VALUE;
}
return true;
}
#endif
//so on and so forth.
You don't. The C++ standard has no concept of directories. It is up to the implementation to turn a string into a file handle. The contents of that string and what it maps to is OS dependent. Keep in mind that C++ can be used to write that OS, so it gets used at a level where asking how to iterate through a directory is not yet defined (because you are writing the directory management code).
Look at your OS API documentation for how to do this. If you need to be portable, you will have to have a bunch of #ifdefs for various OSes.
You need to call OS-specific functions for filesystem traversal, like open() and readdir(). The C standard does not specify any filesystem-related functions.
You don't. Standard C++ doesn't expose to concept of a directory. Specifically it doesn't give any way to list all the files in a directory.
A horrible hack would be to use system() calls and to parse the results. The most reasonable solution would be to use some kind of cross-platform library such as Qt or even POSIX.
On C++17 you can by this way :
#include <filesystem>
#include <iostream>
#include <vector>
namespace fs = std::filesystem;
int main()
{
std::ios_base::sync_with_stdio(false);
for (const auto &entry : fs::recursive_directory_iterator(".")) {
if (entry.path().extension() == ".png") {
std::cout << entry.path().string() << std::endl;
}
}
return 0;
}
If you are on Windows, you can use the FindFirstFile together with FindNextFile API. You can use FindFileData.dwFileAttributes to check if a given path is a file or a directory. If it's a directory, you can recursively repeat the algorithm.
Here, I have put together some code that lists all the files on a Windows machine.
http://dreams-soft.com/projects/traverse-directory
File tree walk ftw is a recursive way to wall the whole directory tree in the path. More details are here.
NOTE : You can also use fts that can skip hidden files like . or .. or .bashrc
#include <ftw.h>
#include <stdio.h>
#include <sys/stat.h>
#include <string.h>
int list(const char *name, const struct stat *status, int type)
{
if (type == FTW_NS)
{
return 0;
}
if (type == FTW_F)
{
printf("0%3o\t%s\n", status->st_mode&0777, name);
}
if (type == FTW_D && strcmp(".", name) != 0)
{
printf("0%3o\t%s/\n", status->st_mode&0777, name);
}
return 0;
}
int main(int argc, char *argv[])
{
if(argc == 1)
{
ftw(".", list, 1);
}
else
{
ftw(argv[1], list, 1);
}
return 0;
}
output looks like following:
0755 ./Shivaji/
0644 ./Shivaji/20200516_204454.png
0644 ./Shivaji/20200527_160408.png
0644 ./Shivaji/20200527_160352.png
0644 ./Shivaji/20200520_174754.png
0644 ./Shivaji/20200520_180103.png
0755 ./Saif/
0644 ./Saif/Snapchat-1751229005.jpg
0644 ./Saif/Snapchat-1356123194.jpg
0644 ./Saif/Snapchat-613911286.jpg
0644 ./Saif/Snapchat-107742096.jpg
0755 ./Milind/
0644 ./Milind/IMG_1828.JPG
0644 ./Milind/IMG_1839.JPG
0644 ./Milind/IMG_1825.JPG
0644 ./Milind/IMG_1831.JPG
0644 ./Milind/IMG_1840.JPG
Let us say if you want to match a filename (example: searching for all the *.jpg, *.jpeg, *.png files.) for a specific needs, use fnmatch.
#include <ftw.h>
#include <stdio.h>
#include <sys/stat.h>
#include <iostream>
#include <fnmatch.h>
static const char *filters[] = {
"*.jpg", "*.jpeg", "*.png"
};
int list(const char *name, const struct stat *status, int type)
{
if (type == FTW_NS)
{
return 0;
}
if (type == FTW_F)
{
int i;
for (i = 0; i < sizeof(filters) / sizeof(filters[0]); i++) {
/* if the filename matches the filter, */
if (fnmatch(filters[i], name, FNM_CASEFOLD) == 0) {
printf("0%3o\t%s\n", status->st_mode&0777, name);
break;
}
}
}
if (type == FTW_D && strcmp(".", name) != 0)
{
//printf("0%3o\t%s/\n", status->st_mode&0777, name);
}
return 0;
}
int main(int argc, char *argv[])
{
if(argc == 1)
{
ftw(".", list, 1);
}
else
{
ftw(argv[1], list, 1);
}
return 0;
}
Answers of getting all file names recursively with C++11 for Windows and Linux(with experimental/filesystem):
For Windows:
#include <io.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <windows.h>
void getFiles_w(string path, vector<string>& files) {
intptr_t hFile = 0;
struct _finddata_t fileinfo;
string p;
if ((hFile = _findfirst(p.assign(path).append("\\*").c_str(), &fileinfo)) != -1) {
do {
if ((fileinfo.attrib & _A_SUBDIR)) {
if (strcmp(fileinfo.name, ".") != 0 && strcmp(fileinfo.name, "..") != 0)
getFiles(p.assign(path).append("/").append(fileinfo.name), files);
}
else {
files.push_back(p.assign(path).append("/").append(fileinfo.name));
}
} while (_findnext(hFile, &fileinfo) == 0);
}
}
For Linux:
#include <experimental/filesystem>
bool getFiles(std::experimental::filesystem::path path, vector<string>& filenames) {
namespace stdfs = std::experimental::filesystem;
// http://en.cppreference.com/w/cpp/experimental/fs/directory_iterator
const stdfs::directory_iterator end{} ;
for (stdfs::directory_iterator iter{path}; iter != end ; ++iter) {
// http://en.cppreference.com/w/cpp/experimental/fs/is_regular_file
if (!stdfs::is_regular_file(*iter)) { // comment out if all names (names of directories tc.) are required
if (getFiles(iter->path(), filenames))
return true;
}
else {
filenames.push_back(iter->path().string()) ;
cout << iter->path().string() << endl;
}
}
return false;
}
Just remember to link -lstdc++fs when you compile it with g++ in Linux.
Employee Visual C++ and WIN API:
bool Parser::queryDIR(string dir_name) {
vector<string> sameLayerFiles;
bool ret = false;
string dir = "";
//employee wide char
dir = dir_name + "\\*.*";;
//employee WIN File API
WIN32_FIND_DATA fd;
WIN32_FIND_DATA fd_dir;
HANDLE hFind = ::FindFirstFile(getWC(dir.c_str()), &fd);
HANDLE hFind_dir = ::FindFirstFile(getWC(dir.c_str()), &fd_dir);
string str_subdir;
string str_tmp;
//recursive call for diving into sub-directories
do {
if ((fd_dir.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ) {
//ignore trival file node
while(true) {
FindNextFile(hFind_dir, &fd_dir);
str_tmp = wc2str(fd_dir.cFileName);
if (str_tmp.compare(".") && str_tmp.compare("..")){
break;
}
}
if ((fd_dir.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ) {
str_subdir = wc2str(fd_dir.cFileName);
ret = queryDIR(dir_name + "\\" + str_subdir);
}
}
} while(::FindNextFile(hFind_dir, &fd_dir));
//iterate same layer files
do {
if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
str_tmp = wc2str(fd.cFileName);
string fname = dir_name + "\\" + str_tmp;
sameLayerFiles.push_back(fname);
}
} while(::FindNextFile(hFind, &fd));
for (std::vector<string>::iterator it=sameLayerFiles.begin(); it!=sameLayerFiles.end(); it++) {
std::cout << "iterated file:" << *it << "..." << std::endl;
//Doing something with every file here
}
return true;
}
Hope my code can help :)
And you can see more details and program screen-shots on My GitHub