stat & S_IFREG in C++ - c++

void fun1(char *fl){
//flNamep : stores the path of our directory
DIR *dip;
struct dirent *dit;
dip = opendir(fl);
if (dip==NULL) {cerr<<"Error\n";exit(-1);}
while ((dit=readdir(dip)))
{
string trun = (dit->d_name);
struct stat buff;
stat(dit->d_name, &buff);
if (((buff.st_mode & S_IFREG)==S_IFREG))
{cout<<"File"<<endl;}
else if (((buff.st_mode & S_IFDIR)==S_IFDIR))
{cout<<"Dir"<<endl;}
}
closedir(dip);
}
Code does not differentiate in dir and files. Am i missing something? I can not use Boost or any other STL. only C Posix Supported files. Need to know were i am wrong.
Updated code as per answer
DIR *dip;
struct dirent *dit;
dip = opendir(flNamep);
if (dip==NULL) {cerr<<"Err\n";exit(-1);}
while ((dit=readdir(dip)))
{
string trun = (dit->d_name);
string fullpath = flNamep;
fullpath+='/';
fullpath+=trun;
if((trun==".") || (trun=="..")) {cout<<"";}
else
{
struct stat buff;
stat(dit->d_name, &buff);
if (((buff.st_mode & S_IFDIR)==S_IFDIR))
{cout<<"Dir"<<endl;}
else
{cout<<"File"<<endl;}
}

I suspect that the stat actually fails with ENOENT (no such file) so buff doesn't contain anything useful.
stat(dit->d_name, &buff); /* dirent.d_name is just the name, not the full path */
You probably want to concatenate fl, "/", d_name. But first of all, check the value returned by stat.

Related

how do i read files in a directory according to their modification time in c++ on windows

Currently I am using dirent.h to iterativly access files in a directory and its sub-directories. It accesses them according to their file names (alphabetically). For some reason I want to access the subdirectories and the files according to their modification time (with the latest modified file being accessed at last). Is it possible to do so?
I am thinking to first traverse through the directories and create a sorted list of the files according to their modification time and use this list to read them accordingly. But I was hoping if there is a better way.
Based on my first thinking and as per the suggestion in the comments.
#include<dirent.h>
typedef struct files {
long long mtime;
string file_path;
bool operator<(const files &rhs)const {
return mtime < rhs.mtime;
}
}files;
using namespace std;
vector<struct files> files_list;
void build_files_list(const char *path) {
struct dirent *entry;
DIR *dp;
if (dp = opendir(path)) {
struct _stat64 buf;
while ((entry = readdir(dp))){
std::string p(path);
p += "\\";
p += entry->d_name;
if (!_stat64(p.c_str(), &buf)){
if (S_ISREG(buf.st_mode)){
files new_file;
new_file.mtime = buf.st_mtime;
new_file.file_path = entry->d_name;
files.push_back(new_file);
}
if (S_ISDIR(buf.st_mode) &&
// the following is to ensure we do not dive into directories "." and ".."
strcmp(entry->d_name, ".") && strcmp(entry->d_name, "..")){
//do nothing
}
}
}
closedir(dp);
}
else{
printf_s("\n\tERROR in openning dir %s\n\n\tPlease enter a correct
directory", path);
}
}
void main(){
char *dir_path="dir_path";
build_files_list(dir_path);
sort(files_list.begin(), files_list.end());
//the rest of things to do
}

count the number of directories in a folder C++ windows

I have written a Java program that at one point counts the number of folders in a directory. I would like to translate this program into C++ (I'm trying to learn it). I've been able to translate most of the program, but I haven't been able to find a way to count the subdirectories of a directory. How would I accomplish this?
Thanks in advance
Here is an implementation using the Win32 API.
SubdirCount takes a directory path string argument and it returns a count of its immediate child subdirectories (as an int). Hidden subdirectories are included, but any named "." or ".." are not counted.
FindFirstFile is a TCHAR-taking alias which ends up as either FindFirstFileA or FindFirstFileW. In order to keep strings TCHAR, without assuming availabilty of CString, the example here includes some awkward code just for appending "/*" to the function's argument.
#include <tchar.h>
#include <windows.h>
int SubdirCount(const TCHAR* parent_path) {
// The hideous string manipulation code below
// prepares a TCHAR wildcard string (sub_wild)
// matching any subdirectory immediately under
// parent_path by appending "\*"
size_t len = _tcslen(parent_path);
const size_t alloc_len = len + 3;
TCHAR* sub_wild = new TCHAR[alloc_len];
_tcscpy_s(sub_wild, alloc_len, parent_path);
if(len && sub_wild[len-1] != _T('\\')) { sub_wild[len++] = _T('\\'); }
sub_wild[len++] = _T('*');
sub_wild[len++] = _T('\0');
// File enumeration starts here
WIN32_FIND_DATA fd;
HANDLE hfind;
int count = 0;
if(INVALID_HANDLE_VALUE != (hfind = FindFirstFile(sub_wild, &fd))) {
do {
if(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
// is_alias_dir is true if directory name is "." or ".."
const bool is_alias_dir = fd.cFileName[0] == _T('.') &&
(!fd.cFileName[1] || (fd.cFileName[1] == _T('.') &&
!fd.cFileName[2]));
count += !is_alias_dir;
}
} while(FindNextFile(hfind, &fd));
FindClose(hfind);
}
delete [] sub_wild;
return count;
}

How can I find the file by its part of name

How can I find the a file by its part of name in c++/linux?
The file full name maybe like:
foo.db.1
or
foo.db.2
How can I find the file by part of its name "foo.db", Thanks
The Posix standard function for your use case is glob(). Earlier somebody posted an easy to use C++ wrapper around it here on Stackoverflow.
For example with:
find /your/path -name "foo.db.*"
It will match all files in /your/path structure whose name is like foo.db.<something>.
If the text after db. is always a number, you can do:
find /your/path -name "foo.db.[0-9]*"
You can also use ls:
ls -l /your/path/ls.db.[0-9]
to get files whose name is like foo.db.<number> or even
ls -l /your/path/ls.db.[0-9]*
to get files whose name is like foo.db.<different numbers>
Do like this:
find /filepath -name "foo.db*"
In C/C++, you can do like this:
void findFile(const char *path)
{
DIR *dir;
struct dirent *entry;
char fileName[] = "foo.db";
if (!(dir = opendir(path)))
return;
if (!(entry = readdir(dir)))
return;
do {
if (entry->d_type == DT_DIR) {
char path[1024];
int len = snprintf(path, sizeof(path)-1, "%s/%s", path, entry->d_name);
path[len] = 0;
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
continue;
if(strstr(fileName, entry->d_name) != NULL) {
printf("%s\n", "", entry->d_name);
}
findFile(path);
}
else
printf(" %s\n", "", entry->d_name);
} while (entry = readdir(dir));
closedir(dir);
}

Size of a directory [duplicate]

This question already has answers here:
How can I find the size of all files located inside a folder?
(13 answers)
Closed 9 years ago.
Is there a way to get the directory size/folder size without actually traversing this directory and adding size of each file in it? Ideally would like to use some library like boost but win api would be ok too.
As far as I am aware you have to do this with iteration on most operating systems.
You could take a look at boost.filesystem, this library has a recursive_directory_iterator, it will iterate though ever file on the system getting accumulation the size.
http://www.boost.org/doc/libs/1_49_0/libs/filesystem/v3/doc/reference.html#Class-recursive_directory_iterator
include <boost/filesystem.hpp>
int main()
{
namespace bf=boost::filesystem;
size_t size=0;
for(bf::recursive_directory_iterator it("path");
it!=bf::recursive_directory_iterator();
++it)
{
if(!bf::is_directory(*it))
size+=bf::file_size(*it);
}
}
PS: you can make this a lot cleaner by using std::accumulate and a lambda I just CBA
I don't think there is something like that, at least no win32 api function.
Natively for windows:
void DirectoryInfo::CalculateSize(std::string _path)
{
WIN32_FIND_DATAA data;
HANDLE sh = NULL;
sh = FindFirstFileA((_path+"\\*").c_str(), &data);
if (sh == INVALID_HANDLE_VALUE )
{
return;
}
do
{
// skip current and parent
if (std::string(data.cFileName).compare(".") != 0 && std::string(data.cFileName).compare("..") != 0)
{
// if found object is ...
if ((data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY)
{
// directory, then search it recursievly
this->CalculateSize(_path+"\\"+data.cFileName);
} else
{
// otherwise get object size and add it to directory size
this->dirSize += (__int64) (data.nFileSizeHigh * (MAXDWORD ) + data.nFileSizeLow);
}
}
} while (FindNextFileA(sh, &data)); // do
FindClose(sh);
}
You must traverse the files. Getting a correct result is tricky if there are hard-links or reparse points in the tree. See Raymond Chen's blog post for details.
Zilog has written quite good answer, but I would make that in similar but different way.
I have my types definition file with:
typedef std::wstring String;
typedef std::vector<String> StringVector;
typedef unsigned long long uint64_t;
and code is:
uint64_t CalculateDirSize(const String &path, StringVector *errVect = NULL, uint64_t size = 0)
{
WIN32_FIND_DATA data;
HANDLE sh = NULL;
sh = FindFirstFile((path + L"\\*").c_str(), &data);
if (sh == INVALID_HANDLE_VALUE )
{
//if we want, store all happened error
if (errVect != NULL)
errVect ->push_back(path);
return size;
}
do
{
// skip current and parent
if (!IsBrowsePath(data.cFileName))
{
// if found object is ...
if ((data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY)
// directory, then search it recursievly
size = CalculateDirSize(path + L"\\" + data.cFileName, NULL, size);
else
// otherwise get object size and add it to directory size
size += (uint64_t) (data.nFileSizeHigh * (MAXDWORD ) + data.nFileSizeLow);
}
} while (FindNextFile(sh, &data)); // do
FindClose(sh);
return size;
}
bool IsBrowsePath(const String& path)
{
return (path == _T(".") || path == _T(".."));
}
This uses UNICODE and returns failed dirs if you want that.
To call use:
StringVector vect;
CalculateDirSize(L"C:\\boost_1_52_0", &vect);
CalculateDirSize(L"C:\\boost_1_52_0");
But never pass size

C++ equivalent of MATLAB's "fileparts" function

In MATLAB there's a nice function called fileparts that takes a full file path and parses it into path, filename (without extension), and extension as in the following example from the documentation:
file = 'H:\user4\matlab\classpath.txt';
[pathstr, name, ext] = fileparts(file)
>> pathstr = H:\user4\matlab
>> name = classpath
>> ext = .txt
So I was wondering if there's an equivalent function in any standard C++ or C libraries that I could use? Or would I have to implement this myself? I realize it's fairly simple, but I figured if there's already something pre-made that would be preferable.
Thanks.
The boost library has a file system component "basic_path" that allows you use iterators to discover each component in the filename. Such a component would be OS specific, and I believe you need to compile boost separately for Windows, Linux etc.
I just wrote this simple function. It behaves similar as Matlab's fileparts and works independent of platform.
struct FileParts
{
string path;
string name;
string ext;
};
FileParts fileparts(string filename)
{
int idx0 = filename.rfind("/");
int idx1 = filename.rfind(".");
FileParts fp;
fp.path = filename.substr(0,idx0+1);
fp.name = filename.substr(idx0+1,idx1-idx0-1);
fp.ext = filename.substr(idx1);
return fp;
}
A platform-independent way with C++11/14.
#include <experimental/filesystem>
namespace fs = std::experimental::filesystem;
void fileparts(string full, string& fpath, string& fname, string& fext)
{
auto source = fs::path(full);
fpath = source.parent_path().string();
fname = source.stem().string();
fext = source.extension().string();
}
...
string fpath, fname, fext;
fileparts(full_file_path,fpath,fname,fext);
Some possible solutions, depending on your OS:
Visual C++ _splitpath function
Win32 Shell Path Handling Functions such as PathFindExtension, PathFindFileName, PathStripPath, PathRemoveExtension, PathRemoveFileSpec
Ekalic's text-only approach is useful, but it didn't check for errors. Here's one that does, and also works with both / and \
struct FileParts
{
std::string path; //!< containing folder, if provided, including trailing slash
std::string name; //!< base file name, without extension
std::string ext; //!< extension, including '.'
};
//! Using only text manipulation, splits a full path into component file parts
FileParts fileparts(const std::string &fullpath)
{
using namespace std;
size_t idxSlash = fullpath.rfind("/");
if (idxSlash == string::npos) {
idxSlash = fullpath.rfind("\\");
}
size_t idxDot = fullpath.rfind(".");
FileParts fp;
if (idxSlash != string::npos && idxDot != string::npos) {
fp.path = fullpath.substr(0, idxSlash + 1);
fp.name = fullpath.substr(idxSlash + 1, idxDot - idxSlash - 1);
fp.ext = fullpath.substr(idxDot);
} else if (idxSlash == string::npos && idxDot == string::npos) {
fp.name = fullpath;
} else if (/* only */ idxSlash == string::npos) {
fp.name = fullpath.substr(0, idxDot);
fp.ext = fullpath.substr(idxDot);
} else { // only idxDot == string::npos
fp.path = fullpath.substr(0, idxSlash + 1);
fp.name = fullpath.substr(idxSlash + 1);
}
return fp;
}