Search for a file in $PATH on Linux in C - c

I would like to test whether GNUPlot is installed on the system on which my program is running.
For that, I figured I'll test for the existence of the gnuplot executable in the user's install locations through stat() call.
However, I don't know how to read the $PATH environment variable in C so I can test for the existence of the file in those locations.

Use the getenv() function.
char *paths = getenv("PATH");
To loop through the parts of the column-separated list of paths, use strchr():
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *dup = strdup(getenv("PATH"));
char *s = dup;
char *p = NULL;
do {
p = strchr(s, ':');
if (p != NULL) {
p[0] = 0;
}
printf("Path in $PATH: %s\n", s);
s = p + 1;
} while (p != NULL);
free(dup);

Use getenv() to inspect the value of a particular environment variable.

To read the PATH environment variable, use getenv("PATH").
However, if you just want to run gnuplot if it's available, and perform some fallback action if it's not, then you should just try to run it (e.g. with fork and execvp or posix_spawnp) and handle the failure case.

Let which do the work for you
if (system("which gnuplot"))
/* not installed or not in path or not executable or some other error */
If you need the full path for some reason, run which with popen.
Or run gnuplot with some flag which makes it return immediately with 0 */
if (system("gnuplot --version"))
/* not installed ... */

I had a similar need and resolved it by copying libc execvp code source. I did in the most cross platform I could think of(I have no guatanty and tested just on linux). If it's not such a matter to you and you care about performances, you should use acess or _acess. Note that there is no error check whatsoever and it will just return NULL or a founded openable file in path.
The accepted answer is sometime not acceptable, when you are willing to run the same small binary over and over, redoing the path search every time by calling execvp can be non negligable overhead.
So here is the code and associated tests, you will be mainely interested in the search_in_path_openable_file function.
.h file:
bool is_openable_file(char* path);
/*Return true if path is a readable file. You can call perror if return false to check what happened*/
char* search_in_path_openable_file(char* file_name);
/*Search into PATH env variable a file_name and return the full path of the first that is openable, NULL if not in path*/
char* search_executable(char* file_name);
/*Search file, if not openable and not absolute path(contain /), look for opennable file in the path. If nothing is openable, return NULL. If something is openable, return it as it is (not guaratented to have a full path, but garatanted to be openable)*/
.c file:
#include "file_info.h"
#include <stdio.h>
#include <string.h> //strcpy
/*I wanted to do a really cross platform way. access or _acess may be better*/
bool is_openable_file(char *path) {
FILE *fp = fopen(path, "r");
if (fp) {
// exists
fclose(fp);
return true;
}
return false;
}
bool is_openable_file_until(char *path_begin, size_t until) {
char old = path_begin[until];
path_begin[until] = 0;
bool res = is_openable_file(path_begin);
path_begin[until] = old;
return res;
}
/*You may thinks that libc would have done this function and use it to implement execp function family, but you would be wrong. They just hardcoded the search in every execp function. Unbelievable.
*
* So this function is a modification of their execvp function.
*
* */
char* search_in_path_openable_file(char* file){
char *path = getenv("PATH");
if (path == NULL)
return NULL;
size_t pathlen = strlen(path);
size_t len = strlen(file) + 1;
int total_max_size=pathlen + len;
char* buf=malloc(sizeof(char)*total_max_size);
if (*file == '\0') {
return NULL;
}
char *name, *p;
/* Copy the file name at the top. */
name = memcpy(buf + pathlen + 1, file, len);
/* And add the slash. */
*--name = '/';
p = path;
do {
char *startp;
path = p;
//Let's avoid this GNU extension.
//p = strchrnul (path, ':');
p = strchr(path, ':');
if (!p)
p = strchr(path, '\0');
if (p == path)
/* Two adjacent colons, or a colon at the beginning or the end
of `PATH' means to search the current directory. */
startp = name + 1;
else
startp = memcpy(name - (p - path), path, p - path);
/* Try to execute this name. If it works, execv will not return. */
if (is_openable_file(startp))
return startp;
} while (*p++ != '\0');
/* We tried every element and none of them worked. */
return NULL;
}
char* search_executable(char* file_name){
if (is_openable_file(file_name)){//See realpath manual bug. Watch out
return file_name;
}
if (strchr (file_name, '/') != NULL) //Don't search when it contains a slash.
return NULL;
return search_in_path_openable_file(file_name);
}
tests (As you see I did not test a lot this function, there may exist some problem, use at your risk):
#include "file_info.h"
#include "munit.h"
#include <stdbool.h>
#include <unistd.h>
static void generate_search_executable(char* test_str, char* expected){
char* res= search_executable(test_str);
if (res==NULL)
munit_assert_ptr(expected,==,NULL );
else
munit_assert_string_equal(expected,res);
}
static void generate_openable(char* test_str, bool expected){
bool res= is_openable_file(test_str);
munit_assert_true(expected==res);
}
static void generate_path_search(char* test_str, char* expected_res){
char* res= search_in_path_openable_file(test_str);
if (res==NULL)
munit_assert_ptr(expected_res,==,NULL );
else
munit_assert_string_equal(expected_res,res);
}
//TODO do for other platform, better test would also set path to a custom folder that we control
#define EXISTING_FILE_NOT_IN_PATH "/usr/include/stdlib.h"
#define EXISTING_FILE_IN_PATH "ls"
#define EXISTING_FILE_IN_PATH_FULL "/bin/ls"
#define NOT_EXISTING_FILE "/usrarfzsvdvwxv/ixvxwvnxcvcelgude/ssdvtdbool.h"
int main() {
generate_openable(EXISTING_FILE_IN_PATH, false);
generate_openable(EXISTING_FILE_NOT_IN_PATH, true);
generate_openable(NOT_EXISTING_FILE, false);
generate_path_search(EXISTING_FILE_IN_PATH, EXISTING_FILE_IN_PATH_FULL);
generate_path_search(NOT_EXISTING_FILE, NULL);
generate_path_search(EXISTING_FILE_NOT_IN_PATH, NULL);
generate_search_executable(EXISTING_FILE_IN_PATH, EXISTING_FILE_IN_PATH_FULL);
generate_search_executable(NOT_EXISTING_FILE, NULL);
generate_search_executable(EXISTING_FILE_NOT_IN_PATH, EXISTING_FILE_NOT_IN_PATH);
generate_search_executable("", NULL );
//test current folder existence(maybe it just depend on path containing .,I am not sure, in that case we should remove thoses tests
generate_search_executable("file_info_test", "file_info_test" );
}

To build on one of the previous answers, you can use getenv to get the contents of PATH and then iterate over its components. Instead of using strchr you can use strsep:
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <stdbool.h>
bool exists(const char fname[])
{
return access(fname, F_OK | X_OK) != -1;
}
bool find_in_path(const char name[], char *fullpath, size_t sz) {
char *paths = strdup(getenv("PATH"));
char *tmp = paths; // to use in free
const char *item;
bool found = false;
while ((item = strsep(&paths, ":")) != NULL) {
snprintf(fullpath, sz, "%s/%s", item, name);
if (exists(fullpath)) {
found = true;
break;
}
}
free(tmp);
return found;
}
int main() {
char fullpath[512];
bool found = find_in_path("uname", fullpath, sizeof(fullpath));
if (found) {
printf("found: %s\n", fullpath);
}
return 0;
}

Using C++17 to get a vector of path elements.
% a.out ls
/bin/ls
#include <iostream>
#include <vector>
#include <cstdlib>
#include <cstring>
#include <unistd.h>
using namespace std;
vector<string> get_paths (string str)
{
vector<string> result;
while(!str.empty())
{
if (auto pos { str.find_first_of (':') }; pos == string::npos)
{
result.push_back(str);
break;
}
else
{
result.emplace_back(str.substr(0, pos));
str.erase(0, pos + 1);
}
}
return move(result);
}
bool exist(const string& fname, int perm=F_OK) { return access(fname.c_str(), perm) == 0; }
int main (int argc, char *argv[])
{
auto result { get_paths(getenv("PATH")) };
for (auto pp : result)
{
string npath { pp };
if (*npath.rbegin() != '/')
npath += '/';
npath += argv[1];
if (exist(npath))
cout << npath << endl;
}
return 0;
}

Related

How to change environment variables in C language

I was working on my game and decided to use eclipse as my compiler. I had to compile it for both platforms: x86 and x64. The trouble started there. There are many dependency files in the system path.
And every time I had to change them in order to change the platform. So, I've created a line to set up my configurations faster and without affect the path itself.
This is the line to add into the path that I've created:
%DRIVE%\mingw\mingw%PLATFORM%\bin;%DRIVE%\Dropbox\Machine\Windows\C\Place\bin\x%PLATFORM%;%DRIVE%\Dropbox\Machine\Windows\C\PLUGIN\x%PLATFORM%\bin;
As you guys can see there are two variables there: %DRIVE% and %PLATFORM%.
I wish to change them with a file that I try to create in c.
Here is the code
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <string.h>
char *strremove(char *str, const char *sub) {
char *p, *q, *r;
if ((q = r = strstr(str, sub)) != NULL) {
size_t len = strlen(sub);
while ((r = strstr(p = r + len, sub)) != NULL) {
while (p < r)
*q++ = *p++;
}
while ((*q++ = *p++) != '\0')
continue;
}
return str;
}
#ifndef HAVE_SETENV
int setenv(const char * variable,const char * value) {
if(!variable || !value)return(0);
int len = strlen(variable)+1+strlen(value)+1;
char * EnvString = calloc(len,sizeof(char));
sprintf(EnvString, "%s=%s", variable, value);
if (!_putenv(EnvString)) {
return (1);
}
if(EnvString)free(EnvString);
return (0);
}
#endif
void change_platform(int argc,char ** argv) {
char * variable = "PLATFORM",* value = "86";
if(argc > 1){
value = argv[1];
}
if (setenv(variable, value)) {
printf("\n environmental variable successfully written");
printf("\n value of the environmental variable written is %s",
getenv(variable));
} else {
printf("\n error in writing the environmental variable");
}
}
int main(int argc, char ** argv) {
change_platform(argc,argv);
getch();
return 0;
}
My code shows the right result inside the program, but when I go and check the system environment itself, nothing changes. Am I doing something wrong.
Detail: I thought it was because of mingw which isn't native from Windows, then I've created I file in Visual c++ too, but it did not work either.
Please remember it affects only the environment of the current process
getenv, _wgetenv
int main( void )
{
char *libvar;
// Get the value of the LIB environment variable.
libvar = getenv( "LIB" ); // C4996
// Note: getenv is deprecated; consider using getenv_s instead
if( libvar != NULL )
printf( "Original LIB variable is: %s\n", libvar );
// Attempt to change path. Note that this only affects the environment
// variable of the current process. The command processor's
// environment is not changed.
_putenv( "LIB=c:\\mylib;c:\\yourlib" ); // C4996
// Note: _putenv is deprecated; consider using putenv_s instead
// Get new value.
libvar = getenv( "LIB" ); // C4996
if( libvar != NULL )
printf( "New LIB variable is: %s\n", libvar );
}

How to check if a file exists in a given path in C?

I am trying to find the file(say marks.txt) in the particular path passed as argument to a function. Is it possible to give the filename and path as arguments to a function which checks if the file exists and prints out the path?
The below function only takes path as argument.
int fileexists(const char *path){
File *ptr = fopen(path, "r");
if (fptr == NULL)
return 0;
fclose(fptr);
return 1;
}
The required function prototype :
int fileexists(const char *path, const char *filename)
There are two parts to this question, and the right answers to them depend on what you're trying to do.
Concatenate a directory name and a file name to form a full path name.
Determine whether a file (referred to by a full path name) exists or not.
Concatenating a directory name and a file name is straightforward. Your friendsstrcpy and strcat will do most of the work. There are a few minor details to be careful of: (a) You'll need a big enough buffer for the full pathname, and you'll need to decide whether to use a fixed-size array (perhaps of size MAX_PATH), or a malloc'ed buffer; (b) you might need to insert an explicit '/' character (and it usually doesn't hurt to stick one in even if the directory string already ends in one); (c) under Windows you might want to use '\\' instead of '/'.
And then determining whether a file named by a full pathname exists is already well answered over at What's the best way to check if a file exists in C?. The big question to ask here is, are you asking whether the file exists in preparation to doing something with the file? If so, you have a serious vulnerability if you check for the file's existence, but then before you do the other thing, something else happens to cause the file to appear or disappear. So rather than checking-and-then-doing, it's usually better to just try doing the other thing, and deal gracefully with any errors.
The function you have checks if the file can be opened, but it will fail for some files that exist but you have no rights to open. I'd use stat instead. To concatenate the path and filename you can use string functions.
The usual Unix C APIs are dismal. It takes lots of effort to do the simplest of things correctly - and even then I'm not sure that I didn't forget some Unix-ism like signal handling or some obscure error cases. I.e. stuff that's rather trivial to get right in modern C++.
I wish someone designed a modern C system API and implemented it for at least Linux, so that our suffering would end...
Usually, string concatenation requires some higher level API to be done while maintaining a modicum of sanity. Thus, the example below uses a strbuilder class to build the string. This makes things vaguely readable and avoids most common mistakes.
#include <assert.h>
#include <errno.h>
#include <limits.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
struct strbuilder {
unsigned items, item;
size_t length, *lengths;
char *str, *dst;
};
bool strbuilder_pass(struct strbuilder *builder, int *rc);
void strcat_str(struct strbuilder *builder, const char *src);
void strcat_c_ifnone(struct strbuilder *builder, char c);
bool strbuilder_is_freed(const struct strbuilder *builder);
int fileExists(const char *path, const char *filename)
{
const char pathSep = '/';
int rc;
struct strbuilder bld = {0};
while (strbuilder_pass(&bld, &rc))
{
strcat_str(&bld, path);
strcat_c_ifnone(&bld, pathSep);
strcat_str(&bld, filename);
if (!rc)
{
struct stat statbuf;
printf("path = %s\n", bld.str);
rc = stat(bld.str, &statbuf);
}
}
assert(strbuilder_is_freed(&bld));
return rc;
}
int main()
{
int rc = fileExists("/", "dev");
assert(rc == 0);
return 0;
}
The string building is controlled by a strbuilder_pass function, which advances the string builder's state through five passes of operation:
Determine the number of items whose width has to be stored (avoids the need to call strlen twice).
Prepare the length storage vector. Determine the length of the buffer needed.
Prepare the output string buffer. Concatenate the elements into the buffer.
Use the output string buffer.
Free the output string buffer.
This API is not particularly special, but fits this use case. Some other ad-hoc approach would work too, but this is IMHO a bit more elegant.
void strbuilder_free(struct strbuilder *builder)
{
free(builder->lengths);
free(builder->str);
memset(builder, 0, sizeof(*builder));
}
bool strbuilder_pass(struct strbuilder *builder, int *rc)
{
if (!builder->length) {// start of pass 1
builder->length = 1; /*term*/
*rc = EAGAIN;
return true;
}
else if (!builder->lengths) // end of pass 1
{
builder->lengths = malloc(sizeof(*builder->lengths) * builder->items);
if (builder->lengths)
return true;
*rc = ENOMEM;
}
else if (!builder->str) // end of pass 2
{
builder->dst = (builder->str = malloc(builder->length));
builder->item = 0;
builder->length = 0;
if (builder->dst) {
*builder->dst = '\0';
return true;
}
*rc = ENOMEM;
}
else if (builder->dst) // end of pass 3
{
while (*builder->dst) { // include optional content
builder->dst++; // skip
builder->length++;
}
builder->dst = NULL;
*rc = 0;
return true;
}
else if (!builder->dst) // end of pass 4 (if any)
{}
else {
*rc = EINVAL;
}
strbuilder_free(builder);
return false;
}
void strcat_str(struct strbuilder *builder, const char *src)
{
if (!src)
return;
if (!builder->lengths) // pass 1
builder->items ++;
else if (!builder->str) // pass 2
{
size_t len = strlen(src);
builder->lengths[builder->item++] = len;
builder->length += len;
}
else if (builder->dst) // pass 3
{
size_t len = builder->lengths[builder->item++];
if (*builder->dst && (!len || *builder->dst != *src))
{
builder->dst++;
builder->length++;
}
memcpy(builder->dst, src, len);
builder->dst += len;
builder->length += len;
*builder->dst = '\0';
}
}
void strcat_c_ifnone(struct strbuilder *builder, char c)
{
if (!builder->lengths) {} // pass 1
else if (!builder->str) // pass 2
{
if (c) builder->length ++;
}
else if (builder->dst) // pass 3
{
if (!builder->length || builder->dst[-1] != c)
*(builder->dst) = c;
}
}
bool strbuilder_is_freed(const struct strbuilder *builder)
{
return !builder || (!builder->lengths && !builder->str);
}
You probably want something like this (no error checking for brevity):
...
#include <string.h> // for str* functions
#include <unistd.h> // for access
#include <stdlib.h> // for malloc
...
int fileexists(const char *path, const char *filename)
{
char *name= malloc(strlen(path) + strlen(filename) + 1);
strcpy(name, path);
strcat(name, filename);
int retval = access(name, F_OK) == 0;
free(name);
return retval;
}
Call like this:
if (fileexists("/some/path/", "somefilename.txt")) ...

C function to remove a directory [duplicate]

How to delete a non empty directory in C or C++? Is there any function? rmdir only deletes empty directory. Please provide a way without using any external library.
Also tell me how to delete a file in C or C++?
You want to write a function (a recursive function is easiest, but can easily run out of stack space on deep directories) that will enumerate the children of a directory. If you find a child that is a directory, you recurse on that. Otherwise, you delete the files inside. When you are done, the directory is empty and you can remove it via the syscall.
To enumerate directories on Unix, you can use opendir(), readdir(), and closedir(). To remove you use rmdir() on an empty directory (i.e. at the end of your function, after deleting the children) and unlink() on a file. Note that on many systems the d_type member in struct dirent is not supported; on these platforms, you will have to use stat() and S_ISDIR(stat.st_mode) to determine if a given path is a directory.
On Windows, you will use FindFirstFile()/FindNextFile() to enumerate, RemoveDirectory() on empty directories, and DeleteFile() to remove files.
Here's an example that might work on Unix (completely untested):
int remove_directory(const char *path) {
DIR *d = opendir(path);
size_t path_len = strlen(path);
int r = -1;
if (d) {
struct dirent *p;
r = 0;
while (!r && (p=readdir(d))) {
int r2 = -1;
char *buf;
size_t len;
/* Skip the names "." and ".." as we don't want to recurse on them. */
if (!strcmp(p->d_name, ".") || !strcmp(p->d_name, ".."))
continue;
len = path_len + strlen(p->d_name) + 2;
buf = malloc(len);
if (buf) {
struct stat statbuf;
snprintf(buf, len, "%s/%s", path, p->d_name);
if (!stat(buf, &statbuf)) {
if (S_ISDIR(statbuf.st_mode))
r2 = remove_directory(buf);
else
r2 = unlink(buf);
}
free(buf);
}
r = r2;
}
closedir(d);
}
if (!r)
r = rmdir(path);
return r;
}
Many unix-like systems (Linux, the BSDs, and OS X, at the very least) have the fts functions for directory traversal.
To recursively delete a directory, perform a depth-first traversal (without following symlinks) and remove every visited file:
int recursive_delete(const char *dir)
{
int ret = 0;
FTS *ftsp = NULL;
FTSENT *curr;
// Cast needed (in C) because fts_open() takes a "char * const *", instead
// of a "const char * const *", which is only allowed in C++. fts_open()
// does not modify the argument.
char *files[] = { (char *) dir, NULL };
// FTS_NOCHDIR - Avoid changing cwd, which could cause unexpected behavior
// in multithreaded programs
// FTS_PHYSICAL - Don't follow symlinks. Prevents deletion of files outside
// of the specified directory
// FTS_XDEV - Don't cross filesystem boundaries
ftsp = fts_open(files, FTS_NOCHDIR | FTS_PHYSICAL | FTS_XDEV, NULL);
if (!ftsp) {
fprintf(stderr, "%s: fts_open failed: %s\n", dir, strerror(errno));
ret = -1;
goto finish;
}
while ((curr = fts_read(ftsp))) {
switch (curr->fts_info) {
case FTS_NS:
case FTS_DNR:
case FTS_ERR:
fprintf(stderr, "%s: fts_read error: %s\n",
curr->fts_accpath, strerror(curr->fts_errno));
break;
case FTS_DC:
case FTS_DOT:
case FTS_NSOK:
// Not reached unless FTS_LOGICAL, FTS_SEEDOT, or FTS_NOSTAT were
// passed to fts_open()
break;
case FTS_D:
// Do nothing. Need depth-first search, so directories are deleted
// in FTS_DP
break;
case FTS_DP:
case FTS_F:
case FTS_SL:
case FTS_SLNONE:
case FTS_DEFAULT:
if (remove(curr->fts_accpath) < 0) {
fprintf(stderr, "%s: Failed to remove: %s\n",
curr->fts_path, strerror(curr->fts_errno));
ret = -1;
}
break;
}
}
finish:
if (ftsp) {
fts_close(ftsp);
}
return ret;
}
If you are using a POSIX compliant OS, you could use nftw() for file tree traversal and remove (removes files or directories). If you are in C++ and your project uses boost, it is not a bad idea to use the Boost.Filesystem as suggested by Manuel.
In the code example below I decided not to traverse symbolic links and mount points (just to avoid a grand removal:) ):
#include <stdio.h>
#include <stdlib.h>
#include <ftw.h>
static int rmFiles(const char *pathname, const struct stat *sbuf, int type, struct FTW *ftwb)
{
if(remove(pathname) < 0)
{
perror("ERROR: remove");
return -1;
}
return 0;
}
int main(int argc, char *argv[])
{
if (argc != 2)
{
fprintf(stderr,"usage: %s path\n",argv[0]);
exit(1);
}
// Delete the directory and its contents by traversing the tree in reverse order, without crossing mount boundaries and symbolic links
if (nftw(argv[1], rmFiles,10, FTW_DEPTH|FTW_MOUNT|FTW_PHYS) < 0)
{
perror("ERROR: ntfw");
exit(1);
}
return 0;
}
The easiest way to do this is with remove_all function of the Boost.Filesystem library. Besides, the resulting code will be portable.
If you want to write something specific for Unix (rmdir) or for Windows (RemoveDirectory) then you'll have to write a function that deletes are subfiles and subfolders recursively.
EDIT
Looks like this question was already asked, in fact someone already recommended Boost's remove_all. So please don't upvote my answer.
C++17 has <experimental\filesystem> which is based on the boost version.
Use std::experimental::filesystem::remove_all to remove recursively.
If you need more control, try std::experimental::filesystem::recursive_directory_iterator.
You can also write your own recursion with the non-resursive version of the iterator.
namespace fs = std::experimental::filesystem;
void IterateRecursively(fs::path path)
{
if (fs::is_directory(path))
{
for (auto & child : fs::directory_iterator(path))
IterateRecursively(child.path());
}
std::cout << path << std::endl;
}
You can use opendir and readdir to read directory entries and unlink to delete them.
//======================================================
// Recursely Delete files using:
// Gnome-Glib & C++11
//======================================================
#include <iostream>
#include <string>
#include <glib.h>
#include <glib/gstdio.h>
using namespace std;
int DirDelete(const string& path)
{
const gchar* p;
GError* gerr;
GDir* d;
int r;
string ps;
string path_i;
cout << "open:" << path << "\n";
d = g_dir_open(path.c_str(), 0, &gerr);
r = -1;
if (d) {
r = 0;
while (!r && (p=g_dir_read_name(d))) {
ps = string{p};
if (ps == "." || ps == "..") {
continue;
}
path_i = path + string{"/"} + p;
if (g_file_test(path_i.c_str(), G_FILE_TEST_IS_DIR) != 0) {
cout << "recurse:" << path_i << "\n";
r = DirDelete(path_i);
}
else {
cout << "unlink:" << path_i << "\n";
r = g_unlink(path_i.c_str());
}
}
g_dir_close(d);
}
if (r == 0) {
r = g_rmdir(path.c_str());
cout << "rmdir:" << path << "\n";
}
return r;
}
How to delete a non empty folder using unlinkat() in c?
Here is my work on it:
/*
* Program to erase the files/subfolders in a directory given as an input
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
void remove_dir_content(const char *path)
{
struct dirent *de;
char fname[300];
DIR *dr = opendir(path);
if(dr == NULL)
{
printf("No file or directory found\n");
return;
}
while((de = readdir(dr)) != NULL)
{
int ret = -1;
struct stat statbuf;
sprintf(fname,"%s/%s",path,de->d_name);
if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
continue;
if(!stat(fname, &statbuf))
{
if(S_ISDIR(statbuf.st_mode))
{
printf("Is dir: %s\n",fname);
printf("Err: %d\n",ret = unlinkat(dirfd(dr),fname,AT_REMOVEDIR));
if(ret != 0)
{
remove_dir_content(fname);
printf("Err: %d\n",ret = unlinkat(dirfd(dr),fname,AT_REMOVEDIR));
}
}
else
{
printf("Is file: %s\n",fname);
printf("Err: %d\n",unlink(fname));
}
}
}
closedir(dr);
}
void main()
{
char str[10],str1[20] = "../",fname[300]; // Use str,str1 as your directory path where it's files & subfolders will be deleted.
printf("Enter the dirctory name: ");
scanf("%s",str);
strcat(str1,str);
printf("str1: %s\n",str1);
remove_dir_content(str1); //str1 indicates the directory path
}
This code will open particular directory and iterate over all files and delete them which are under that directory. After that it will delete empty directory at the end.
/**
* #file RemoveDir.c
* #author Om Patel (ompatel1861#gmail.com)
* #brief This program will remove non empty directory.
* #version 0.1
* #date 2022-05-31
*
* #copyright Copyright (c) 2022
*
*/
#include<stdio.h>
#include<string.h>
#include<dirent.h>
#include <unistd.h>
int main()
{
DIR* dir = opendir("OUTPUT/Aakash");
struct dirent* entity;
entity = readdir(dir);
while(entity != NULL){
char path[30] ="OUTPUT/Aakash/";
printf("%s\n",entity->d_name);
strcat(path,entity->d_name);
printf("PAth: %s\n",path);
remove(path);
entity = readdir(dir);
}
char path1[30] ="OUTPUT/Aakash";
rmdir(path1);
closedir(dir);
char out[20]="OUTPUT/";
char fol_file[30];
sprintf(fol_file,"%s\\",out);
printf("%s",fol_file);
return 0;
}

Return list of strings containing the list of files in a directory in C [duplicate]

How can I determine the list of files in a directory from inside my C or C++ code?
I'm not allowed to execute the ls command and parse the results from within my program.
UPDATE 2017:
In C++17 there is now an official way to list files of your file system: std::filesystem. There is an excellent answer from Shreevardhan below with this source code:
#include <string>
#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;
int main()
{
std::string path = "/path/to/directory";
for (const auto & entry : fs::directory_iterator(path))
std::cout << entry.path() << std::endl;
}
Old Answer:
In small and simple tasks I do not use boost, I use dirent.h. It is available as a standard header in UNIX, and also available for Windows via a compatibility layer created by Toni Ronkko.
DIR *dir;
struct dirent *ent;
if ((dir = opendir ("c:\\src\\")) != NULL) {
/* print all the files and directories within directory */
while ((ent = readdir (dir)) != NULL) {
printf ("%s\n", ent->d_name);
}
closedir (dir);
} else {
/* could not open directory */
perror ("");
return EXIT_FAILURE;
}
It is just a small header file and does most of the simple stuff you need without using a big template-based approach like boost (no offence, I like boost!).
C++17 now has a std::filesystem::directory_iterator, which can be used as
#include <string>
#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;
int main() {
std::string path = "/path/to/directory";
for (const auto & entry : fs::directory_iterator(path))
std::cout << entry.path() << std::endl;
}
Also, std::filesystem::recursive_directory_iterator can iterate the subdirectories as well.
Unfortunately the C++ standard does not define a standard way of working with files and folders in this way.
Since there is no cross platform way, the best cross platform way is to use a library such as the boost filesystem module.
Cross platform boost method:
The following function, given a directory path and a file name, recursively searches the directory and its sub-directories for the file name, returning a bool, and if successful, the path to the file that was found.
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;
}
Source from the boost page mentioned above.
For Unix/Linux based systems:
You can use opendir / readdir / closedir.
Sample code which searches a directory for entry ``name'' is:
len = strlen(name);
dirp = opendir(".");
while ((dp = readdir(dirp)) != NULL)
if (dp->d_namlen == len && !strcmp(dp->d_name, name)) {
(void)closedir(dirp);
return FOUND;
}
(void)closedir(dirp);
return NOT_FOUND;
Source code from the above man pages.
For a windows based systems:
You can use the Win32 API FindFirstFile / FindNextFile / FindClose functions.
The following C++ example shows you a minimal use of FindFirstFile.
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
void _tmain(int argc, TCHAR *argv[])
{
WIN32_FIND_DATA FindFileData;
HANDLE hFind;
if( argc != 2 )
{
_tprintf(TEXT("Usage: %s [target_file]\n"), argv[0]);
return;
}
_tprintf (TEXT("Target file is %s\n"), argv[1]);
hFind = FindFirstFile(argv[1], &FindFileData);
if (hFind == INVALID_HANDLE_VALUE)
{
printf ("FindFirstFile failed (%d)\n", GetLastError());
return;
}
else
{
_tprintf (TEXT("The first file found is %s\n"),
FindFileData.cFileName);
FindClose(hFind);
}
}
Source code from the above msdn pages.
One function is enough, you don't need to use any 3rd-party library (for Windows).
#include <Windows.h>
vector<string> get_all_files_names_within_folder(string folder)
{
vector<string> names;
string search_path = folder + "/*.*";
WIN32_FIND_DATA fd;
HANDLE hFind = ::FindFirstFile(search_path.c_str(), &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(fd.cFileName);
}
}while(::FindNextFile(hFind, &fd));
::FindClose(hFind);
}
return names;
}
PS: as mentioned by #Sebastian, you could change *.* to *.ext in order to get only the EXT-files (i.e. of a specific type) in that directory.
For a C only solution, please check this out. It only requires an extra header:
https://github.com/cxong/tinydir
tinydir_dir dir;
tinydir_open(&dir, "/path/to/dir");
while (dir.has_next)
{
tinydir_file file;
tinydir_readfile(&dir, &file);
printf("%s", file.name);
if (file.is_dir)
{
printf("/");
}
printf("\n");
tinydir_next(&dir);
}
tinydir_close(&dir);
Some advantages over other options:
It's portable - wraps POSIX dirent and Windows FindFirstFile
It uses readdir_r where available, which means it's (usually) threadsafe
Supports Windows UTF-16 via the same UNICODE macros
It is C90 so even very ancient compilers can use it
I recommend using glob with this reusable wrapper. It generates a vector<string> corresponding to file paths that fit the glob pattern:
#include <glob.h>
#include <vector>
using std::vector;
vector<string> globVector(const string& pattern){
glob_t glob_result;
glob(pattern.c_str(),GLOB_TILDE,NULL,&glob_result);
vector<string> files;
for(unsigned int i=0;i<glob_result.gl_pathc;++i){
files.push_back(string(glob_result.gl_pathv[i]));
}
globfree(&glob_result);
return files;
}
Which can then be called with a normal system wildcard pattern such as:
vector<string> files = globVector("./*");
I think, below snippet can be used to list all the files.
#include <stdio.h>
#include <dirent.h>
#include <sys/types.h>
int main(int argc, char** argv) {
list_dir("myFolderName");
return EXIT_SUCCESS;
}
static void list_dir(const char *path) {
struct dirent *entry;
DIR *dir = opendir(path);
if (dir == NULL) {
return;
}
while ((entry = readdir(dir)) != NULL) {
printf("%s\n",entry->d_name);
}
closedir(dir);
}
This is the structure used (present in dirent.h):
struct dirent {
ino_t d_ino; /* inode number */
off_t d_off; /* offset to the next dirent */
unsigned short d_reclen; /* length of this record */
unsigned char d_type; /* type of file */
char d_name[256]; /* filename */
};
Here is a very simple code in C++11 using boost::filesystem library to get file names in a directory (excluding folder names):
#include <string>
#include <iostream>
#include <boost/filesystem.hpp>
using namespace std;
using namespace boost::filesystem;
int main()
{
path p("D:/AnyFolder");
for (auto i = directory_iterator(p); i != directory_iterator(); i++)
{
if (!is_directory(i->path())) //we eliminate directories
{
cout << i->path().filename().string() << endl;
}
else
continue;
}
}
Output is like:
file1.txt
file2.dat
Why not use glob()?
#include <glob.h>
glob_t glob_result;
glob("/your_directory/*",GLOB_TILDE,NULL,&glob_result);
for(unsigned int i=0; i<glob_result.gl_pathc; ++i){
cout << glob_result.gl_pathv[i] << endl;
}
Try boost for x-platform method
http://www.boost.org/doc/libs/1_38_0/libs/filesystem/doc/index.htm
or just use your OS specific file stuff.
Check out this class which uses the win32 api. Just construct an instance by providing the foldername from which you want the listing then call the getNextFile method to get the next filename from the directory. I think it needs windows.h and stdio.h.
class FileGetter{
WIN32_FIND_DATAA found;
HANDLE hfind;
char folderstar[255];
int chk;
public:
FileGetter(char* folder){
sprintf(folderstar,"%s\\*.*",folder);
hfind = FindFirstFileA(folderstar,&found);
//skip .
FindNextFileA(hfind,&found);
}
int getNextFile(char* fname){
//skips .. when called for the first time
chk=FindNextFileA(hfind,&found);
if (chk)
strcpy(fname, found.cFileName);
return chk;
}
};
GNU Manual FTW
http://www.gnu.org/software/libc/manual/html_node/Simple-Directory-Lister.html#Simple-Directory-Lister
Also, sometimes it's good to go right to the source (pun intended). You can learn a lot by looking at the innards of some of the most common commands in Linux. I've set up a simple mirror of GNU's coreutils on github (for reading).
https://github.com/homer6/gnu_coreutils/blob/master/src/ls.c
Maybe this doesn't address Windows, but a number of cases of using Unix variants can be had by using these methods.
Hope that helps...
Shreevardhan answer works great. But if you want to use it in c++14 just make a change namespace fs = experimental::filesystem;
i.e.,
#include <string>
#include <iostream>
#include <filesystem>
using namespace std;
namespace fs = experimental::filesystem;
int main()
{
string path = "C:\\splits\\";
for (auto & p : fs::directory_iterator(path))
cout << p << endl;
int n;
cin >> n;
}
#include <string>
#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;
int main() {
std::string path = "/path/to/directory";
for (const auto & entry : fs::directory_iterator(path))
std::cout << entry.path() << std::endl;
}
I hope this code help you.
#include <windows.h>
#include <iostream>
#include <string>
#include <vector>
using namespace std;
string wchar_t2string(const wchar_t *wchar)
{
string str = "";
int index = 0;
while(wchar[index] != 0)
{
str += (char)wchar[index];
++index;
}
return str;
}
wchar_t *string2wchar_t(const string &str)
{
wchar_t wchar[260];
int index = 0;
while(index < str.size())
{
wchar[index] = (wchar_t)str[index];
++index;
}
wchar[index] = 0;
return wchar;
}
vector<string> listFilesInDirectory(string directoryName)
{
WIN32_FIND_DATA FindFileData;
wchar_t * FileName = string2wchar_t(directoryName);
HANDLE hFind = FindFirstFile(FileName, &FindFileData);
vector<string> listFileNames;
listFileNames.push_back(wchar_t2string(FindFileData.cFileName));
while (FindNextFile(hFind, &FindFileData))
listFileNames.push_back(wchar_t2string(FindFileData.cFileName));
return listFileNames;
}
void main()
{
vector<string> listFiles;
listFiles = listFilesInDirectory("C:\\*.txt");
for each (string str in listFiles)
cout << str << endl;
}
char **getKeys(char *data_dir, char* tablename, int *num_keys)
{
char** arr = malloc(MAX_RECORDS_PER_TABLE*sizeof(char*));
int i = 0;
for (;i < MAX_RECORDS_PER_TABLE; i++)
arr[i] = malloc( (MAX_KEY_LEN+1) * sizeof(char) );
char *buf = (char *)malloc( (MAX_KEY_LEN+1)*sizeof(char) );
snprintf(buf, MAX_KEY_LEN+1, "%s/%s", data_dir, tablename);
DIR* tableDir = opendir(buf);
struct dirent* getInfo;
readdir(tableDir); // ignore '.'
readdir(tableDir); // ignore '..'
i = 0;
while(1)
{
getInfo = readdir(tableDir);
if (getInfo == 0)
break;
strcpy(arr[i++], getInfo->d_name);
}
*(num_keys) = i;
return arr;
}
This implementation realizes your purpose, dynamically filling an array of strings with the content of the specified directory.
int exploreDirectory(const char *dirpath, char ***list, int *numItems) {
struct dirent **direntList;
int i;
errno = 0;
if ((*numItems = scandir(dirpath, &direntList, NULL, alphasort)) == -1)
return errno;
if (!((*list) = malloc(sizeof(char *) * (*numItems)))) {
fprintf(stderr, "Error in list allocation for file list: dirpath=%s.\n", dirpath);
exit(EXIT_FAILURE);
}
for (i = 0; i < *numItems; i++) {
(*list)[i] = stringDuplication(direntList[i]->d_name);
}
for (i = 0; i < *numItems; i++) {
free(direntList[i]);
}
free(direntList);
return 0;
}
This works for me. I'm sorry if I cannot remember the source. It is probably from a man page.
#include <ftw.h>
int AnalizeDirectoryElement (const char *fpath,
const struct stat *sb,
int tflag,
struct FTW *ftwbuf) {
if (tflag == FTW_F) {
std::string strFileName(fpath);
DoSomethingWith(strFileName);
}
return 0;
}
void WalkDirectoryTree (const char * pchFileName) {
int nFlags = 0;
if (nftw(pchFileName, AnalizeDirectoryElement, 20, nFlags) == -1) {
perror("nftw");
}
}
int main() {
WalkDirectoryTree("some_dir/");
}
you can get all direct of files in your root directory by using std::experimental:: filesystem::directory_iterator(). Then, read the name of these pathfiles.
#include <iostream>
#include <filesystem>
#include <string>
#include <direct.h>
using namespace std;
namespace fs = std::experimental::filesystem;
void ShowListFile(string path)
{
for(auto &p: fs::directory_iterator(path)) /*get directory */
cout<<p.path().filename()<<endl; // get file name
}
int main() {
ShowListFile("C:/Users/dell/Pictures/Camera Roll/");
getchar();
return 0;
}
This answer should work for Windows users that have had trouble getting this working with Visual Studio with any of the other answers.
Download the dirent.h file from the github page. But is better to just use the Raw dirent.h file and follow my steps below (it is how I got it to work).
Github page for dirent.h for Windows: Github page for dirent.h
Raw Dirent File: Raw dirent.h File
Go to your project and Add a new Item (Ctrl+Shift+A). Add a header file (.h) and name it dirent.h.
Paste the Raw dirent.h File code into your header.
Include "dirent.h" in your code.
Put the below void filefinder() method in your code and call it from your main function or edit the function how you want to use it.
#include <stdio.h>
#include <string.h>
#include "dirent.h"
string path = "C:/folder"; //Put a valid path here for folder
void filefinder()
{
DIR *directory = opendir(path.c_str());
struct dirent *direntStruct;
if (directory != NULL) {
while (direntStruct = readdir(directory)) {
printf("File Name: %s\n", direntStruct->d_name); //If you are using <stdio.h>
//std::cout << direntStruct->d_name << std::endl; //If you are using <iostream>
}
}
closedir(directory);
}
I tried to follow the example given in both answers and it might be worth noting that it appears as though std::filesystem::directory_entry has been changed to not have an overload of the << operator. Instead of std::cout << p << std::endl; I had to use the following to be able to compile and get it working:
#include <iostream>
#include <filesystem>
#include <string>
namespace fs = std::filesystem;
int main() {
std::string path = "/path/to/directory";
for(const auto& p : fs::directory_iterator(path))
std::cout << p.path() << std::endl;
}
trying to pass p on its own to std::cout << resulted in a missing overload error.
Peter Parker's solution, but without using for:
#include <algorithm>
#include <filesystem>
#include <ranges>
#include <vector>
using namespace std;
int main() {
vector<filesystem::path> filePaths;
ranges::transform(filesystem::directory_iterator("."),
back_inserter(filePaths), [](const auto& dirFile){return dirFile.path();} );
}
System call it!
system( "dir /b /s /a-d * > file_names.txt" );
Then just read the file.
EDIT: This answer should be considered a hack, but it really does work (albeit in a platform specific way) if you don't have access to more elegant solutions.
Since files and sub directories of a directory are generally stored in a tree structure, an intuitive way is to use DFS algorithm to recursively traverse each of them.
Here is an example in windows operating system by using basic file functions in io.h. You can replace these functions in other platform. What I want to express is that the basic idea of DFS perfectly meets this problem.
#include<io.h>
#include<iostream.h>
#include<string>
using namespace std;
void TraverseFilesUsingDFS(const string& folder_path){
_finddata_t file_info;
string any_file_pattern = folder_path + "\\*";
intptr_t handle = _findfirst(any_file_pattern.c_str(),&file_info);
//If folder_path exsist, using any_file_pattern will find at least two files "." and "..",
//of which "." means current dir and ".." means parent dir
if (handle == -1){
cerr << "folder path not exist: " << folder_path << endl;
exit(-1);
}
//iteratively check each file or sub_directory in current folder
do{
string file_name=file_info.name; //from char array to string
//check whtether it is a sub direcotry or a file
if (file_info.attrib & _A_SUBDIR){
if (file_name != "." && file_name != ".."){
string sub_folder_path = folder_path + "\\" + file_name;
TraverseFilesUsingDFS(sub_folder_path);
cout << "a sub_folder path: " << sub_folder_path << endl;
}
}
else
cout << "file name: " << file_name << endl;
} while (_findnext(handle, &file_info) == 0);
//
_findclose(handle);
}
Building on what herohuyongtao posted and a few other posts:
http://www.cplusplus.com/forum/general/39766/
What is the expected input type of FindFirstFile?
How to convert wstring into string?
This is a Windows solution.
Since I wanted to pass in std::string and return a vector of strings I had to make a couple conversions.
#include <string>
#include <Windows.h>
#include <vector>
#include <locale>
#include <codecvt>
std::vector<std::string> listFilesInDir(std::string path)
{
std::vector<std::string> names;
//Convert string to wstring
std::wstring search_path = std::wstring_convert<std::codecvt_utf8<wchar_t>>().from_bytes(path);
WIN32_FIND_DATA fd;
HANDLE hFind = FindFirstFile(search_path.c_str(), &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))
{
//convert from wide char to narrow char array
char ch[260];
char DefChar = ' ';
WideCharToMultiByte(CP_ACP, 0, fd.cFileName, -1, ch, 260, &DefChar, NULL);
names.push_back(ch);
}
}
while (::FindNextFile(hFind, &fd));
::FindClose(hFind);
}
return names;
}
Based on the answers above
#include <vector>
#include <string>
#include <algorithm>
#ifdef _WIN32
#include <windows.h>
std::vector<std::string> files_in_directory(std::string path)
{
std::vector<std::string> files;
// check directory exists
char fullpath[MAX_PATH];
GetFullPathName(path.c_str(), MAX_PATH, fullpath, 0);
std::string fp(fullpath);
if (GetFileAttributes(fp.c_str()) != FILE_ATTRIBUTE_DIRECTORY)
return files;
// get file names
WIN32_FIND_DATA findfiledata;
HANDLE hFind = FindFirstFile((LPCSTR)(fp + "\\*").c_str(), &findfiledata);
if (hFind != INVALID_HANDLE_VALUE)
{
do
{
files.push_back(findfiledata.cFileName);
}
while (FindNextFile(hFind, &findfiledata));
FindClose(hFind);
}
// delete current and parent directories
files.erase(std::find(files.begin(), files.end(), "."));
files.erase(std::find(files.begin(), files.end(), ".."));
// sort in alphabetical order
std::sort(files.begin(), files.end());
return files;
}
#else
#include <dirent.h>
std::vector<std::string> files_in_directory(std::string directory)
{
std::vector<std::string> files;
// open directory
DIR *dir;
dir = opendir(directory.c_str());
if (dir == NULL)
return files;
// get file names
struct dirent *ent;
while ((ent = readdir(dir)) != NULL)
files.push_back(ent->d_name);
closedir(dir);
// delete current and parent directories
files.erase(std::find(files.begin(), files.end(), "."));
files.erase(std::find(files.begin(), files.end(), ".."));
// sort in alphabetical order
std::sort(files.begin(), files.end());
return files;
}
#endif // _WIN32
Shreevardhan's design also works great for traversing subdirectories:
#include <string>
#include <iostream>
#include <filesystem>
using namespace std;
namespace fs = filesystem;
int main()
{
string path = "\\path\\to\\directory";
// string path = "/path/to/directory";
for (auto & p : fs::recursive_directory_iterator(path))
cout << p.path() << endl;
}
Compilation: cl /EHsc /W4 /WX /std:c++17 ListFiles.cpp
Simply in Linux use following ASCI C style code
#include <bits/stdc++.h>
#include <dirent.h>
using namespace std;
int main(){
DIR *dpdf;
struct dirent *epdf;
dpdf = opendir("./");
if (dpdf != NULL){
while (epdf = readdir(dpdf)){
cout << epdf->d_name << std::endl;
}
}
closedir(dpdf);
return 0;
}
Hope this helps!
Just something that I want to share and thank you for the reading material. Play around with the function for a bit to understand it. You may like it. e stood for extension, p is for path, and s is for path separator.
If the path is passed without ending separator, a separator will be appended to the path. For the extension, if an empty string is inputted then the function will return any file that does not have an extension in its name. If a single star was inputted than all files in the directory will be returned. If e length is greater than 0 but is not a single * then a dot will be prepended to e if e had not contained a dot at the zero position.
For a returning value. If a zero-length map is returned then nothing was found but the directory was open okay. If index 999 is available from the return value but the map size is only 1 then that meant there was a problem with opening the directory path.
Note that for efficiency, this function can be split into 3 smaller functions. On top of that, you can create a caller function that will detect which function it is going to call based on the input. Why is that more efficient? Said if you are going to grab everything that is a file, doing that method the subfunction that built for grabbing all the files will just grab all that are files and does not need to evaluate any other unnecessary condition everytime it found a file.
That would also apply to when you grab files that do not have an extension. A specific built function for that purpose would only evaluate for weather if the object found is a file and then whether or not if the name of the file has a dot in it.
The saving may not be much if you only read directories with not so much files. But if you are reading a mass amount of directory or if the directory has couple hundred thousands of files, it could be a huge saving.
#include <stdio.h>
#include <sys/stat.h>
#include <iostream>
#include <dirent.h>
#include <map>
std::map<int, std::string> getFile(std::string p, std::string e = "", unsigned char s = '/'){
if ( p.size() > 0 ){
if (p.back() != s) p += s;
}
if ( e.size() > 0 ){
if ( e.at(0) != '.' && !(e.size() == 1 && e.at(0) == '*') ) e = "." + e;
}
DIR *dir;
struct dirent *ent;
struct stat sb;
std::map<int, std::string> r = {{999, "FAILED"}};
std::string temp;
int f = 0;
bool fd;
if ( (dir = opendir(p.c_str())) != NULL ){
r.erase (999);
while ((ent = readdir (dir)) != NULL){
temp = ent->d_name;
fd = temp.find(".") != std::string::npos? true : false;
temp = p + temp;
if (stat(temp.c_str(), &sb) == 0 && S_ISREG(sb.st_mode)){
if ( e.size() == 1 && e.at(0) == '*' ){
r[f] = temp;
f++;
} else {
if (e.size() == 0){
if ( fd == false ){
r[f] = temp;
f++;
}
continue;
}
if (e.size() > temp.size()) continue;
if ( temp.substr(temp.size() - e.size()) == e ){
r[f] = temp;
f++;
}
}
}
}
closedir(dir);
return r;
} else {
return r;
}
}
void printMap(auto &m){
for (const auto &p : m) {
std::cout << "m[" << p.first << "] = " << p.second << std::endl;
}
}
int main(){
std::map<int, std::string> k = getFile("./", "");
printMap(k);
return 0;
}
#include<iostream>
#include <dirent.h>
using namespace std;
char ROOT[]={'.'};
void listfiles(char* path){
DIR * dirp = opendir(path);
dirent * dp;
while ( (dp = readdir(dirp)) !=NULL ) {
cout << dp->d_name << " size " << dp->d_reclen<<std::endl;
}
(void)closedir(dirp);
}
int main(int argc, char **argv)
{
char* path;
if (argc>1) path=argv[1]; else path=ROOT;
cout<<"list files in ["<<path<<"]"<<std::endl;
listfiles(path);
return 0;
}

List files from directory C/C++ [duplicate]

How can I determine the list of files in a directory from inside my C or C++ code?
I'm not allowed to execute the ls command and parse the results from within my program.
UPDATE 2017:
In C++17 there is now an official way to list files of your file system: std::filesystem. There is an excellent answer from Shreevardhan below with this source code:
#include <string>
#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;
int main()
{
std::string path = "/path/to/directory";
for (const auto & entry : fs::directory_iterator(path))
std::cout << entry.path() << std::endl;
}
Old Answer:
In small and simple tasks I do not use boost, I use dirent.h. It is available as a standard header in UNIX, and also available for Windows via a compatibility layer created by Toni Ronkko.
DIR *dir;
struct dirent *ent;
if ((dir = opendir ("c:\\src\\")) != NULL) {
/* print all the files and directories within directory */
while ((ent = readdir (dir)) != NULL) {
printf ("%s\n", ent->d_name);
}
closedir (dir);
} else {
/* could not open directory */
perror ("");
return EXIT_FAILURE;
}
It is just a small header file and does most of the simple stuff you need without using a big template-based approach like boost (no offence, I like boost!).
C++17 now has a std::filesystem::directory_iterator, which can be used as
#include <string>
#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;
int main() {
std::string path = "/path/to/directory";
for (const auto & entry : fs::directory_iterator(path))
std::cout << entry.path() << std::endl;
}
Also, std::filesystem::recursive_directory_iterator can iterate the subdirectories as well.
Unfortunately the C++ standard does not define a standard way of working with files and folders in this way.
Since there is no cross platform way, the best cross platform way is to use a library such as the boost filesystem module.
Cross platform boost method:
The following function, given a directory path and a file name, recursively searches the directory and its sub-directories for the file name, returning a bool, and if successful, the path to the file that was found.
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;
}
Source from the boost page mentioned above.
For Unix/Linux based systems:
You can use opendir / readdir / closedir.
Sample code which searches a directory for entry ``name'' is:
len = strlen(name);
dirp = opendir(".");
while ((dp = readdir(dirp)) != NULL)
if (dp->d_namlen == len && !strcmp(dp->d_name, name)) {
(void)closedir(dirp);
return FOUND;
}
(void)closedir(dirp);
return NOT_FOUND;
Source code from the above man pages.
For a windows based systems:
You can use the Win32 API FindFirstFile / FindNextFile / FindClose functions.
The following C++ example shows you a minimal use of FindFirstFile.
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
void _tmain(int argc, TCHAR *argv[])
{
WIN32_FIND_DATA FindFileData;
HANDLE hFind;
if( argc != 2 )
{
_tprintf(TEXT("Usage: %s [target_file]\n"), argv[0]);
return;
}
_tprintf (TEXT("Target file is %s\n"), argv[1]);
hFind = FindFirstFile(argv[1], &FindFileData);
if (hFind == INVALID_HANDLE_VALUE)
{
printf ("FindFirstFile failed (%d)\n", GetLastError());
return;
}
else
{
_tprintf (TEXT("The first file found is %s\n"),
FindFileData.cFileName);
FindClose(hFind);
}
}
Source code from the above msdn pages.
One function is enough, you don't need to use any 3rd-party library (for Windows).
#include <Windows.h>
vector<string> get_all_files_names_within_folder(string folder)
{
vector<string> names;
string search_path = folder + "/*.*";
WIN32_FIND_DATA fd;
HANDLE hFind = ::FindFirstFile(search_path.c_str(), &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(fd.cFileName);
}
}while(::FindNextFile(hFind, &fd));
::FindClose(hFind);
}
return names;
}
PS: as mentioned by #Sebastian, you could change *.* to *.ext in order to get only the EXT-files (i.e. of a specific type) in that directory.
For a C only solution, please check this out. It only requires an extra header:
https://github.com/cxong/tinydir
tinydir_dir dir;
tinydir_open(&dir, "/path/to/dir");
while (dir.has_next)
{
tinydir_file file;
tinydir_readfile(&dir, &file);
printf("%s", file.name);
if (file.is_dir)
{
printf("/");
}
printf("\n");
tinydir_next(&dir);
}
tinydir_close(&dir);
Some advantages over other options:
It's portable - wraps POSIX dirent and Windows FindFirstFile
It uses readdir_r where available, which means it's (usually) threadsafe
Supports Windows UTF-16 via the same UNICODE macros
It is C90 so even very ancient compilers can use it
I recommend using glob with this reusable wrapper. It generates a vector<string> corresponding to file paths that fit the glob pattern:
#include <glob.h>
#include <vector>
using std::vector;
vector<string> globVector(const string& pattern){
glob_t glob_result;
glob(pattern.c_str(),GLOB_TILDE,NULL,&glob_result);
vector<string> files;
for(unsigned int i=0;i<glob_result.gl_pathc;++i){
files.push_back(string(glob_result.gl_pathv[i]));
}
globfree(&glob_result);
return files;
}
Which can then be called with a normal system wildcard pattern such as:
vector<string> files = globVector("./*");
I think, below snippet can be used to list all the files.
#include <stdio.h>
#include <dirent.h>
#include <sys/types.h>
int main(int argc, char** argv) {
list_dir("myFolderName");
return EXIT_SUCCESS;
}
static void list_dir(const char *path) {
struct dirent *entry;
DIR *dir = opendir(path);
if (dir == NULL) {
return;
}
while ((entry = readdir(dir)) != NULL) {
printf("%s\n",entry->d_name);
}
closedir(dir);
}
This is the structure used (present in dirent.h):
struct dirent {
ino_t d_ino; /* inode number */
off_t d_off; /* offset to the next dirent */
unsigned short d_reclen; /* length of this record */
unsigned char d_type; /* type of file */
char d_name[256]; /* filename */
};
Here is a very simple code in C++11 using boost::filesystem library to get file names in a directory (excluding folder names):
#include <string>
#include <iostream>
#include <boost/filesystem.hpp>
using namespace std;
using namespace boost::filesystem;
int main()
{
path p("D:/AnyFolder");
for (auto i = directory_iterator(p); i != directory_iterator(); i++)
{
if (!is_directory(i->path())) //we eliminate directories
{
cout << i->path().filename().string() << endl;
}
else
continue;
}
}
Output is like:
file1.txt
file2.dat
Why not use glob()?
#include <glob.h>
glob_t glob_result;
glob("/your_directory/*",GLOB_TILDE,NULL,&glob_result);
for(unsigned int i=0; i<glob_result.gl_pathc; ++i){
cout << glob_result.gl_pathv[i] << endl;
}
Try boost for x-platform method
http://www.boost.org/doc/libs/1_38_0/libs/filesystem/doc/index.htm
or just use your OS specific file stuff.
Check out this class which uses the win32 api. Just construct an instance by providing the foldername from which you want the listing then call the getNextFile method to get the next filename from the directory. I think it needs windows.h and stdio.h.
class FileGetter{
WIN32_FIND_DATAA found;
HANDLE hfind;
char folderstar[255];
int chk;
public:
FileGetter(char* folder){
sprintf(folderstar,"%s\\*.*",folder);
hfind = FindFirstFileA(folderstar,&found);
//skip .
FindNextFileA(hfind,&found);
}
int getNextFile(char* fname){
//skips .. when called for the first time
chk=FindNextFileA(hfind,&found);
if (chk)
strcpy(fname, found.cFileName);
return chk;
}
};
GNU Manual FTW
http://www.gnu.org/software/libc/manual/html_node/Simple-Directory-Lister.html#Simple-Directory-Lister
Also, sometimes it's good to go right to the source (pun intended). You can learn a lot by looking at the innards of some of the most common commands in Linux. I've set up a simple mirror of GNU's coreutils on github (for reading).
https://github.com/homer6/gnu_coreutils/blob/master/src/ls.c
Maybe this doesn't address Windows, but a number of cases of using Unix variants can be had by using these methods.
Hope that helps...
Shreevardhan answer works great. But if you want to use it in c++14 just make a change namespace fs = experimental::filesystem;
i.e.,
#include <string>
#include <iostream>
#include <filesystem>
using namespace std;
namespace fs = experimental::filesystem;
int main()
{
string path = "C:\\splits\\";
for (auto & p : fs::directory_iterator(path))
cout << p << endl;
int n;
cin >> n;
}
#include <string>
#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;
int main() {
std::string path = "/path/to/directory";
for (const auto & entry : fs::directory_iterator(path))
std::cout << entry.path() << std::endl;
}
I hope this code help you.
#include <windows.h>
#include <iostream>
#include <string>
#include <vector>
using namespace std;
string wchar_t2string(const wchar_t *wchar)
{
string str = "";
int index = 0;
while(wchar[index] != 0)
{
str += (char)wchar[index];
++index;
}
return str;
}
wchar_t *string2wchar_t(const string &str)
{
wchar_t wchar[260];
int index = 0;
while(index < str.size())
{
wchar[index] = (wchar_t)str[index];
++index;
}
wchar[index] = 0;
return wchar;
}
vector<string> listFilesInDirectory(string directoryName)
{
WIN32_FIND_DATA FindFileData;
wchar_t * FileName = string2wchar_t(directoryName);
HANDLE hFind = FindFirstFile(FileName, &FindFileData);
vector<string> listFileNames;
listFileNames.push_back(wchar_t2string(FindFileData.cFileName));
while (FindNextFile(hFind, &FindFileData))
listFileNames.push_back(wchar_t2string(FindFileData.cFileName));
return listFileNames;
}
void main()
{
vector<string> listFiles;
listFiles = listFilesInDirectory("C:\\*.txt");
for each (string str in listFiles)
cout << str << endl;
}
char **getKeys(char *data_dir, char* tablename, int *num_keys)
{
char** arr = malloc(MAX_RECORDS_PER_TABLE*sizeof(char*));
int i = 0;
for (;i < MAX_RECORDS_PER_TABLE; i++)
arr[i] = malloc( (MAX_KEY_LEN+1) * sizeof(char) );
char *buf = (char *)malloc( (MAX_KEY_LEN+1)*sizeof(char) );
snprintf(buf, MAX_KEY_LEN+1, "%s/%s", data_dir, tablename);
DIR* tableDir = opendir(buf);
struct dirent* getInfo;
readdir(tableDir); // ignore '.'
readdir(tableDir); // ignore '..'
i = 0;
while(1)
{
getInfo = readdir(tableDir);
if (getInfo == 0)
break;
strcpy(arr[i++], getInfo->d_name);
}
*(num_keys) = i;
return arr;
}
This implementation realizes your purpose, dynamically filling an array of strings with the content of the specified directory.
int exploreDirectory(const char *dirpath, char ***list, int *numItems) {
struct dirent **direntList;
int i;
errno = 0;
if ((*numItems = scandir(dirpath, &direntList, NULL, alphasort)) == -1)
return errno;
if (!((*list) = malloc(sizeof(char *) * (*numItems)))) {
fprintf(stderr, "Error in list allocation for file list: dirpath=%s.\n", dirpath);
exit(EXIT_FAILURE);
}
for (i = 0; i < *numItems; i++) {
(*list)[i] = stringDuplication(direntList[i]->d_name);
}
for (i = 0; i < *numItems; i++) {
free(direntList[i]);
}
free(direntList);
return 0;
}
This works for me. I'm sorry if I cannot remember the source. It is probably from a man page.
#include <ftw.h>
int AnalizeDirectoryElement (const char *fpath,
const struct stat *sb,
int tflag,
struct FTW *ftwbuf) {
if (tflag == FTW_F) {
std::string strFileName(fpath);
DoSomethingWith(strFileName);
}
return 0;
}
void WalkDirectoryTree (const char * pchFileName) {
int nFlags = 0;
if (nftw(pchFileName, AnalizeDirectoryElement, 20, nFlags) == -1) {
perror("nftw");
}
}
int main() {
WalkDirectoryTree("some_dir/");
}
you can get all direct of files in your root directory by using std::experimental:: filesystem::directory_iterator(). Then, read the name of these pathfiles.
#include <iostream>
#include <filesystem>
#include <string>
#include <direct.h>
using namespace std;
namespace fs = std::experimental::filesystem;
void ShowListFile(string path)
{
for(auto &p: fs::directory_iterator(path)) /*get directory */
cout<<p.path().filename()<<endl; // get file name
}
int main() {
ShowListFile("C:/Users/dell/Pictures/Camera Roll/");
getchar();
return 0;
}
This answer should work for Windows users that have had trouble getting this working with Visual Studio with any of the other answers.
Download the dirent.h file from the github page. But is better to just use the Raw dirent.h file and follow my steps below (it is how I got it to work).
Github page for dirent.h for Windows: Github page for dirent.h
Raw Dirent File: Raw dirent.h File
Go to your project and Add a new Item (Ctrl+Shift+A). Add a header file (.h) and name it dirent.h.
Paste the Raw dirent.h File code into your header.
Include "dirent.h" in your code.
Put the below void filefinder() method in your code and call it from your main function or edit the function how you want to use it.
#include <stdio.h>
#include <string.h>
#include "dirent.h"
string path = "C:/folder"; //Put a valid path here for folder
void filefinder()
{
DIR *directory = opendir(path.c_str());
struct dirent *direntStruct;
if (directory != NULL) {
while (direntStruct = readdir(directory)) {
printf("File Name: %s\n", direntStruct->d_name); //If you are using <stdio.h>
//std::cout << direntStruct->d_name << std::endl; //If you are using <iostream>
}
}
closedir(directory);
}
I tried to follow the example given in both answers and it might be worth noting that it appears as though std::filesystem::directory_entry has been changed to not have an overload of the << operator. Instead of std::cout << p << std::endl; I had to use the following to be able to compile and get it working:
#include <iostream>
#include <filesystem>
#include <string>
namespace fs = std::filesystem;
int main() {
std::string path = "/path/to/directory";
for(const auto& p : fs::directory_iterator(path))
std::cout << p.path() << std::endl;
}
trying to pass p on its own to std::cout << resulted in a missing overload error.
Peter Parker's solution, but without using for:
#include <algorithm>
#include <filesystem>
#include <ranges>
#include <vector>
using namespace std;
int main() {
vector<filesystem::path> filePaths;
ranges::transform(filesystem::directory_iterator("."),
back_inserter(filePaths), [](const auto& dirFile){return dirFile.path();} );
}
System call it!
system( "dir /b /s /a-d * > file_names.txt" );
Then just read the file.
EDIT: This answer should be considered a hack, but it really does work (albeit in a platform specific way) if you don't have access to more elegant solutions.
Since files and sub directories of a directory are generally stored in a tree structure, an intuitive way is to use DFS algorithm to recursively traverse each of them.
Here is an example in windows operating system by using basic file functions in io.h. You can replace these functions in other platform. What I want to express is that the basic idea of DFS perfectly meets this problem.
#include<io.h>
#include<iostream.h>
#include<string>
using namespace std;
void TraverseFilesUsingDFS(const string& folder_path){
_finddata_t file_info;
string any_file_pattern = folder_path + "\\*";
intptr_t handle = _findfirst(any_file_pattern.c_str(),&file_info);
//If folder_path exsist, using any_file_pattern will find at least two files "." and "..",
//of which "." means current dir and ".." means parent dir
if (handle == -1){
cerr << "folder path not exist: " << folder_path << endl;
exit(-1);
}
//iteratively check each file or sub_directory in current folder
do{
string file_name=file_info.name; //from char array to string
//check whtether it is a sub direcotry or a file
if (file_info.attrib & _A_SUBDIR){
if (file_name != "." && file_name != ".."){
string sub_folder_path = folder_path + "\\" + file_name;
TraverseFilesUsingDFS(sub_folder_path);
cout << "a sub_folder path: " << sub_folder_path << endl;
}
}
else
cout << "file name: " << file_name << endl;
} while (_findnext(handle, &file_info) == 0);
//
_findclose(handle);
}
Building on what herohuyongtao posted and a few other posts:
http://www.cplusplus.com/forum/general/39766/
What is the expected input type of FindFirstFile?
How to convert wstring into string?
This is a Windows solution.
Since I wanted to pass in std::string and return a vector of strings I had to make a couple conversions.
#include <string>
#include <Windows.h>
#include <vector>
#include <locale>
#include <codecvt>
std::vector<std::string> listFilesInDir(std::string path)
{
std::vector<std::string> names;
//Convert string to wstring
std::wstring search_path = std::wstring_convert<std::codecvt_utf8<wchar_t>>().from_bytes(path);
WIN32_FIND_DATA fd;
HANDLE hFind = FindFirstFile(search_path.c_str(), &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))
{
//convert from wide char to narrow char array
char ch[260];
char DefChar = ' ';
WideCharToMultiByte(CP_ACP, 0, fd.cFileName, -1, ch, 260, &DefChar, NULL);
names.push_back(ch);
}
}
while (::FindNextFile(hFind, &fd));
::FindClose(hFind);
}
return names;
}
Based on the answers above
#include <vector>
#include <string>
#include <algorithm>
#ifdef _WIN32
#include <windows.h>
std::vector<std::string> files_in_directory(std::string path)
{
std::vector<std::string> files;
// check directory exists
char fullpath[MAX_PATH];
GetFullPathName(path.c_str(), MAX_PATH, fullpath, 0);
std::string fp(fullpath);
if (GetFileAttributes(fp.c_str()) != FILE_ATTRIBUTE_DIRECTORY)
return files;
// get file names
WIN32_FIND_DATA findfiledata;
HANDLE hFind = FindFirstFile((LPCSTR)(fp + "\\*").c_str(), &findfiledata);
if (hFind != INVALID_HANDLE_VALUE)
{
do
{
files.push_back(findfiledata.cFileName);
}
while (FindNextFile(hFind, &findfiledata));
FindClose(hFind);
}
// delete current and parent directories
files.erase(std::find(files.begin(), files.end(), "."));
files.erase(std::find(files.begin(), files.end(), ".."));
// sort in alphabetical order
std::sort(files.begin(), files.end());
return files;
}
#else
#include <dirent.h>
std::vector<std::string> files_in_directory(std::string directory)
{
std::vector<std::string> files;
// open directory
DIR *dir;
dir = opendir(directory.c_str());
if (dir == NULL)
return files;
// get file names
struct dirent *ent;
while ((ent = readdir(dir)) != NULL)
files.push_back(ent->d_name);
closedir(dir);
// delete current and parent directories
files.erase(std::find(files.begin(), files.end(), "."));
files.erase(std::find(files.begin(), files.end(), ".."));
// sort in alphabetical order
std::sort(files.begin(), files.end());
return files;
}
#endif // _WIN32
Shreevardhan's design also works great for traversing subdirectories:
#include <string>
#include <iostream>
#include <filesystem>
using namespace std;
namespace fs = filesystem;
int main()
{
string path = "\\path\\to\\directory";
// string path = "/path/to/directory";
for (auto & p : fs::recursive_directory_iterator(path))
cout << p.path() << endl;
}
Compilation: cl /EHsc /W4 /WX /std:c++17 ListFiles.cpp
Simply in Linux use following ASCI C style code
#include <bits/stdc++.h>
#include <dirent.h>
using namespace std;
int main(){
DIR *dpdf;
struct dirent *epdf;
dpdf = opendir("./");
if (dpdf != NULL){
while (epdf = readdir(dpdf)){
cout << epdf->d_name << std::endl;
}
}
closedir(dpdf);
return 0;
}
Hope this helps!
Just something that I want to share and thank you for the reading material. Play around with the function for a bit to understand it. You may like it. e stood for extension, p is for path, and s is for path separator.
If the path is passed without ending separator, a separator will be appended to the path. For the extension, if an empty string is inputted then the function will return any file that does not have an extension in its name. If a single star was inputted than all files in the directory will be returned. If e length is greater than 0 but is not a single * then a dot will be prepended to e if e had not contained a dot at the zero position.
For a returning value. If a zero-length map is returned then nothing was found but the directory was open okay. If index 999 is available from the return value but the map size is only 1 then that meant there was a problem with opening the directory path.
Note that for efficiency, this function can be split into 3 smaller functions. On top of that, you can create a caller function that will detect which function it is going to call based on the input. Why is that more efficient? Said if you are going to grab everything that is a file, doing that method the subfunction that built for grabbing all the files will just grab all that are files and does not need to evaluate any other unnecessary condition everytime it found a file.
That would also apply to when you grab files that do not have an extension. A specific built function for that purpose would only evaluate for weather if the object found is a file and then whether or not if the name of the file has a dot in it.
The saving may not be much if you only read directories with not so much files. But if you are reading a mass amount of directory or if the directory has couple hundred thousands of files, it could be a huge saving.
#include <stdio.h>
#include <sys/stat.h>
#include <iostream>
#include <dirent.h>
#include <map>
std::map<int, std::string> getFile(std::string p, std::string e = "", unsigned char s = '/'){
if ( p.size() > 0 ){
if (p.back() != s) p += s;
}
if ( e.size() > 0 ){
if ( e.at(0) != '.' && !(e.size() == 1 && e.at(0) == '*') ) e = "." + e;
}
DIR *dir;
struct dirent *ent;
struct stat sb;
std::map<int, std::string> r = {{999, "FAILED"}};
std::string temp;
int f = 0;
bool fd;
if ( (dir = opendir(p.c_str())) != NULL ){
r.erase (999);
while ((ent = readdir (dir)) != NULL){
temp = ent->d_name;
fd = temp.find(".") != std::string::npos? true : false;
temp = p + temp;
if (stat(temp.c_str(), &sb) == 0 && S_ISREG(sb.st_mode)){
if ( e.size() == 1 && e.at(0) == '*' ){
r[f] = temp;
f++;
} else {
if (e.size() == 0){
if ( fd == false ){
r[f] = temp;
f++;
}
continue;
}
if (e.size() > temp.size()) continue;
if ( temp.substr(temp.size() - e.size()) == e ){
r[f] = temp;
f++;
}
}
}
}
closedir(dir);
return r;
} else {
return r;
}
}
void printMap(auto &m){
for (const auto &p : m) {
std::cout << "m[" << p.first << "] = " << p.second << std::endl;
}
}
int main(){
std::map<int, std::string> k = getFile("./", "");
printMap(k);
return 0;
}
#include<iostream>
#include <dirent.h>
using namespace std;
char ROOT[]={'.'};
void listfiles(char* path){
DIR * dirp = opendir(path);
dirent * dp;
while ( (dp = readdir(dirp)) !=NULL ) {
cout << dp->d_name << " size " << dp->d_reclen<<std::endl;
}
(void)closedir(dirp);
}
int main(int argc, char **argv)
{
char* path;
if (argc>1) path=argv[1]; else path=ROOT;
cout<<"list files in ["<<path<<"]"<<std::endl;
listfiles(path);
return 0;
}

Resources