-
Notifications
You must be signed in to change notification settings - Fork 12
Filesystem
Joshua Z. Zhang edited this page Sep 21, 2015
·
3 revisions
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.
- 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.
- 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.