Number of files in a directory...

7

73blazer

Hello,
I'm writing some C++ code, and I need to be able to find the number of
files in a given directory. Is it possible under AIX4.3.3 with C++ 3.6.4?
I cannot seem to locate anything of this nature in the docs, aside from
creating an array with 'scandir'
(http://publib.boulder.ibm.com/doc_link/en_US/a_doc_lib/libs/basetrf2/scandir.htm#A12F0c9)
which will also give me the number of enties in that array. This seems a
little overkill. I'm fairly new to C++, any suggestions would be most
appreciated.
Thanks.

Ken
 
J

Jack Klein

Hello,
I'm writing some C++ code, and I need to be able to find the number of
files in a given directory. Is it possible under AIX4.3.3 with C++ 3.6.4?

It may be possible under your operating system using your compiler,
provided that they provide some non-standard system-specific
extension. There is no way at all to do this using standard C++, the
topic of this group, which has no support for directory structures at
all.
I cannot seem to locate anything of this nature in the docs, aside from
creating an array with 'scandir'
(http://publib.boulder.ibm.com/doc_link/en_US/a_doc_lib/libs/basetrf2/scandir.htm#A12F0c9)
which will also give me the number of enties in that array. This seems a
little overkill. I'm fairly new to C++, any suggestions would be most
appreciated.
Thanks.

Ken

I would suggest posting to a support group for AIX, if there is one,
or the generic
 
R

Roger Leigh

73blazer said:
I'm writing some C++ code, and I need to be able to find the number of
files in a given directory. Is it possible under AIX4.3.3 with C++
3.6.4?

Yes. Your C library should have calls for this. Note this is UNIX
functionality: C++ knows nothing about directories. See opendir(3),
readdir(3), closedir(3).
I'm fairly new to C++, any suggestions would be most appreciated.

When I was new to C++, I wrote a "dirstream" class around the above
UNIX library functions, which follows (I believe they are fairly
common). Note: it could be better written, I just hope you find it
useful. Please note it's licensed under the GNU GPL; it may only be
used in other GNU GPL licenced programs.

Now I know a little more, I should have written it to use input
iterators, rather than creating a dirstream extraction operator (á la
ifstream). It should perhaps also throw an exception in the
constructor if opendir() fails, rather than setting an error flag.
I'm not sure what's best here--I don't like throwing exceptions unless
absolutely necessary.

It should also a deque rather than a vector for its dirstream
buffering, but it works quite well in my experience.

If all you want is the number of files, then using the above functions
directly will have less overhead.


Regards,
Roger


// dirstream - C++ stream version of C dirents -*- C++ -*-
// Copyright (C) 2003 Roger Leigh <rleigh AT debian DOT org>
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

#ifndef DIRSTREAM_H
#define DIRSTREAM_H 1

#include <iostream>
#include <vector>
#include <string>

#include <sys/types.h>
#include <dirent.h>

/**
* A class to access information about the files in a directory. This
* is a wrapper around the UNIX opendir(3), readdir(3) and closedir(3)
* functions, which are used to read a stream of "dirents" through
* multiple readdir() calls.
*
* dirstream calls opendir() and closedir() automatically, and
* represents each dirent as a dirstream::direntry. Like reading from
* an istream by pulling data out with the >> "extraction operator",
* direntries are also extracted from the dirstream with the >>
* operator.
*/
class dirstream
{
public:

/**
* The constructor.
* @param dir the directory to read.
*/
dirstream(const char *dir);

/**
* The constructor.
* @param dir the directory to read.
*/
dirstream(const std::string& dir);

/// The destructor.
virtual ~dirstream();

/**
* A class to represent an entry in a dirstream. It is a wrapper
* around the dirent structure declared in dirent.h
*
* The direntry is only valid during the lifetime of an open
* dirstream. Once the directory is closed, when the dirstream is
* destroyed, or its close() method called, the direntry can no
* longer be safely used. On many systems, including Linux, this
* does not matter, but the Single UNIX Specification makes no
* garuantees about this.
*/
class direntry
{
public:
/// The constructor.
direntry();

/**
* The constructor.
* @param entry the dirent to initialise the class with.
*/
direntry(const struct dirent *entry);

/**
* The copy constructor.
* @param orig the class to copy.
*/
direntry(const dirstream::direntry& orig);

/// The destructor.
virtual ~direntry();

/**
* Get the dirent inode number (d_ino).
* @returns the inode number.
*/
long inode() const;

/**
* Get the file type (d_type).
* @returns the file type.
*/
unsigned char type() const;

/**
* Get the file name (d_name).
* @returns a reference to a string containing the name.
*/
const std::string& name() const;

/**
* Get the dirent.
* @returns a reference to the underlying dirent.
*/
struct dirent& dirent();

private:
/// The underlying dirent the class is wrapping.
struct dirent data;

/// A string form of data.d_name.
std::string sname;
}; // class direntry

/**
* Open a directory for reading. This uses the opendir(3) call to
* open the underlying DIR stream. Any previously open directory is
* closed before opening the new one. The dirstream error state is
* set is the open fails.
* @param dirname the directory to read.
* @see close()
*/
void open(const char *dirname);

/**
* Close the directory. This uses the closedir(3) call to close the
* underlying DIR stream. All cached data is deleted and the error
* state set until open() is called.
* @see open()
*/
void close();

/**
* Check for End Of File.
* @returns true if the dirstream is empty, otherwise false.
*/
bool eof();

/**
* Check for errors. If there is an error, the dirstream is
* unusable until the next open() call.
* @returns true if the dirstream is in an error state, otherwise
* false.
*/
bool bad();

private:

/**
* A list of direntries represents the directory stream as a LIFO
* stack.
*/
std::vector<direntry> data;

/**
* Read dirents from the underlying DIR stream into the data vector.
* @param quantity the number of dirents to read.
*/
void read(int quantity=1);

/**
* The overloaded extraction operator. This is used to pull
* direntries from a dirstream.
*/
friend dirstream& operator >> (dirstream& in_stream, direntry& entry);

/// The underlying DIR stream
DIR *dir;

/// Error status
bool error;
};

#endif // DIRSTREAM_H


// dirstream - C++ stream version of C dirents -*- C++ -*-
// Copyright (C) 2003 Roger Leigh <rleigh AT debian DOT org>
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

#include <cstring>

#include <errno.h>

#include "dirstream.h"


dirstream::direntry::direntry()
{
// set the dirent data to zero
std::memset(&data, 0, sizeof(struct dirent));
sname.clear();
}

dirstream::direntry::direntry(const struct dirent *entry)
{
// set the dirent data
std::memcpy(&data, entry, sizeof(struct dirent));
sname = data.d_name;
}

dirstream::direntry::direntry(const dirstream::direntry& orig)
{
memcpy(&data, &orig.data, sizeof(struct dirent));
sname = data.d_name;
}

dirstream::direntry::~direntry()
{
// do nothing
}

long
dirstream::direntry::inode() const
{
return data.d_ino;
}

unsigned char
dirstream::direntry::type() const
{
return data.d_type;
}

const std::string&
dirstream::direntry::name() const
{
return sname;
}

struct dirent&
dirstream::direntry::dirent()
{
return data;
}


dirstream::dirstream(const char *dirname)
{
dir = NULL;
error = false;
open(dirname);
}

dirstream::dirstream(const std::string& dirname)
{
dir = NULL;
error = false;
open(dirname.c_str());
}

dirstream::~dirstream()
{
close();
}

void
dirstream::eek:pen(const char *dirname)
{
dir = opendir(dirname);
if (dir == NULL)
error = true;
else
error = false;
read();
}

void
dirstream::read(int quantity)
{
int i;

if (dir == NULL)
return;

for (i=0; i<quantity; i++)
{
//std::cerr << "Read one entry" << std::endl;

struct dirent* entry;
entry = readdir(dir);

if (entry == NULL) // EOF or error
{
//std::cerr << "Directory read error: ";
if (errno == EBADF) // error
{
error = true;
//std::cerr << "bad directory stream";
}
//else
//std::cerr << "end of stream";
//std::cerr << std::endl;
return;
}

direntry newentry(entry); // make a direntry
data.push_back(newentry); // push onto the end of the list
}
}

// close the directory
// this also clears all the direntry data
void
dirstream::close()
{
if (dir)
closedir(dir); // don't throw an exception -- it could be called
// in the destructor
dir = NULL;
data.clear(); // clear all data
error = true;
}


bool
dirstream::eof()
{
if (data.empty())
return true;
return false;
}

bool
dirstream::bad()
{
return error;
}


dirstream& operator >> (dirstream& in_stream, dirstream::direntry& entry)
{
in_stream.read(); // read a new entry
if (in_stream.eof() == false) // not at end of file
{
// std::cerr << "Assigning direntry" << std::endl;
entry = in_stream.data.front(); // assign next direntry to entry
in_stream.data.erase(in_stream.data.begin()); // remove the entry
// std::cerr << in_stream.data.size() << std::endl;
}
else // blank the direntry
std::memset(&entry, 0, sizeof(dirstream::direntry));

return in_stream;
}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top