Skip to content
Joshua Z. Zhang edited this page Sep 21, 2015 · 3 revisions

Filesystem utility functions

Filesystem functions are temporary workaround since boost::filesystem is only a proposal to c++11.

I put filesystem related stuff in two sub-namespaces, zz::os, zz::fs.

The rationale behind that is to separate OS dependent codes and higher abstract codes.

Higher level class which has uniform behaviors cross-platform (zz::fs)

  • fs::Path: class to handle path.
// handle current directory
fs::Path path(".");
std::cout << path.exist() << std::endl; // true
std::cout << path.is_dir() << std::endl; // true
std::cout << path.is_file() << std::endl; // false
std::cout << path.abs_path() << std::endl; // absolute path

fs::Path path2("./tmp/tmp.txt");
std::cout << path.is_file() << std::endl; // check if file exist
std::cout << path.filename() << std::endl; // return filename if exist
std::cout << path.relative_path() << std::endl; // relative path to cwd
  • fs::Directory: class to handle directories and sub-directories, for example, provide a iterator to go through every sub-dir and file in a root folder.
fs::Directory dir("images", true); // search recursively

// print all in images folder
for (auto iter = dir.begin(); iter != dir.end(); ++iter)
{
    // iterator points to each fs::Path object
    std::cout << iter->abs_path() << std::endl; // print abs path
}

// I only want *.jpg files, use filter
dir.filter("*.jpg");
for (auto iter : dir) // c++ 11 for range
{
    std::cout << iter.filename() << std::endl; // print filenames
}

// search another folder, only txt files
fs::Directory dir2("/tmp/logs/", "*.txt", false); // not recursive
for (auto iter : dir2)
{
    ...
}

  • fs::FileEditor: class that can read/write file.
  • fs::FileReader: class that can read file only.

Usually in c++, if you want to create a file, e.g. /tmp/log/output.txt, you have to:

// create /tmp/log directory
#if windows
    int status = CreateDirectory("/tmp/log"); 
    // or int s = _mkdir("/tmp/log");
    // or int s =_wmkdir(L"/tmp/log"); if the path is unicode encoded.
#elif linux
    int r = mkdir("/tmp/log");
#elif macos
    ...
#elif xxx
    ...
#endif
// if /tmp does not exist, you have to create /tmp first. What if a more complicated path?
// there is so much work you should do here

// okay, suppose directory created, create a fstream then
std::ofstream fs("/tmp/log/output.txt");
// check open status
if (!fs.is_open()) retry or report error??
// write 
fs << "your msg" << std::endl;

You have to consider so much things in such a simple case, however, with FileEditor:

fs::FileEditor fe("/tmp/log/output.txt", true, 5, 10); // retry 5 times every 10ms if failed to open
if (!fe.is_open()) error_handler(); // If still fail to open, something is wrong
fe << "your msg" << os::endl();
// Done. 

FileReader do the frequently used functions for you

fs::FileReader fr("test.txt");
std::cout << "lines: " << fr.count_lines() << std::endl; // count number of lines in this text file
std::cout << "next line: " << fr.next_line() << std::endl; // print the next line
int n = fr.goto_line(100); // jump to line 100 for read
//assert(n == 100); // may not be able to jump to wherever you want, reached end/badbit/closed/etc...
std::cout << "next line: " << fr.next_line() << std::endl; // print the next line

FileEditor and FileReader support unicode strings, so you can use it to open and write non-ASCII files.

Low-level functions (zz::os)

  • os::is_file(...): check file existence
  • os::is_directory(...): check directory existence
  • os::create_directory(...): create directory
  • os::create_directory_recursive(...): make sure create directory such as /tmp/tmp2/tmp3, even if /tmp does not exist. It will traverse through top-to-bottom, do all the check for you.
  • os::endl(): OS dependent new line character, for poxis system, "\n", for windows, "\r\n".
  • os::current_working_directory(): get cwd in portable way.
  • os::absolute_path(): get absolute path.
  • os::remove_dir/os::remove_file/os::remove_all: delete dir/files, recursively or not.
  • A lot more

Please check the full documentation here.