Problem
You need to remove a directory, and you want to do it portably, i.e., without using OS-specific APIs.
Solution
On most platforms, you will be able to use the rmdir system call that is shipped with most compilers as part of the C headers. There is no standard C++, portable way to remove a directory. rmdir takes on different forms in different OSs, but regardless, you can use it to remove a directory. See Example 10-17 for a short program that removes a directory.
Example 10-17. Removing a directory
#include #include using namespace std; int main(int argc, char** argv) { if (argc < 2) { cerr << "Usage: " << argv[0] << " [dir name]" << endl; return(EXIT_FAILURE); } if (rmdir(argv[1]) == -1) { // Remove the directory cerr << "Error: " << strerror(errno) << endl;; return(EXIT_FAILURE); } }
Discussion
The signature of rmdir is the same on most OSs, but the header file where it is declared is not. On Windows, it is declared in , and on Unix, it is declared in . It takes one parameter (the directory name), returns -1 if there is an error, and sets errno to the corresponding error number. You can get the implementation-defined error text by calling strerror or perror.
If the target directory is not empty rmdir will return an error. To list the contents of a directory, to enumerate them for deletion, etc., see Recipe 10.12.
If you want portability, and don't want to write a bunch of #ifdefs around the various OS-specific directory functions, you should consider using the Boost Filesystem library. The Boost Filesystem library uses the concept of a path to refer to a directory or file, and paths can be removed with a single function, remove.
The function removeRecurse in Example 10-18 recursively removes a directory and all of its contents. The most important part is the remove function (which is boost::filesystem::remove, not a standard library function). It takes a path argument, and removes it if it is a file or an empty directory, but it doesn't remove a directory that contains files.
Example 10-18. Removing a directory with Boost
#include #include #include #include #include using namespace std; using namespace boost::filesystem; void removeRecurse(const path& p) { // First, remove the contents of the directory directory_iterator end; for (directory_iterator it(p); it != end; ++it) { if (is_directory(*it)) { removeRecurse(*it); } else { remove(*it); } } // Then, remove the directory itself remove(p); } int main(int argc, char** argv) { if (argc != 2) { cerr << "Usage: " << argv[0] << " [dir name] "; return(EXIT_FAILURE); } path thePath = system_complete(path(argv[1], native)); if (!exists(thePath)) { cerr << "Error: the directory " << thePath.string( ) << " does not exist. "; return(EXIT_FAILURE); } try { removeRecurse(thePath); } catch (exception& e) { cerr << e.what( ) << endl; return(EXIT_FAILURE); } return(EXIT_SUCCESS); }
The code that iterates through the directory contents requires some explanation, and that is the subject of Recipe 10.12.
The Boost Filesystem library is handy, but remember that Boost is not a formal standard and therefore is not guaranteed to run everywhere. If you examine the source code for the Boost Filesystem library, you will notice that essentially, it compiles native OS calls based on the target platform. If portability is not a concern, consult your OS's proprietary filesystem API, which will most likely offer more flexibility.
See Also
Recipe 10.12
Building C++ Applications
Code Organization
Numbers
Strings and Text
Dates and Times
Managing Data with Containers
Algorithms
Classes
Exceptions and Safety
Streams and Files
Science and Mathematics
Multithreading
Internationalization
XML
Miscellaneous
Index