Sane C++ Libraries
C++ Platform Abstraction Libraries
Loading...
Searching...
No Matches
File System

🟩 File System operations { exists, copy, delete } for { files and directories }

SaneCppFileSystem.h is a library enabling manipulation of files and directories.

Quick Sheet

// Make all operations relative to applicationRootDirectory
// Create a nested directory structure with some files too
SC_TEST_EXPECT(fs.makeDirectoryRecursive("copyDirectory/subdirectory"));
SC_TEST_EXPECT(fs.write("copyDirectory/testFile.txt", "asdf"));
SC_TEST_EXPECT(fs.existsAndIsFile("copyDirectory/testFile.txt"));
SC_TEST_EXPECT(fs.write("copyDirectory/subdirectory/testFile.txt", "asdf"));
// Copy the directory (recursively)
SC_TEST_EXPECT(fs.copyDirectory("copyDirectory", "COPY_copyDirectory"));
// Check that file exists in the new copied directory
SC_TEST_EXPECT(fs.existsAndIsFile("COPY_copyDirectory/testFile.txt"));
SC_TEST_EXPECT(fs.existsAndIsFile("COPY_copyDirectory/subdirectory/testFile.txt"));
// Copying again fails (because we're not overwriting)
SC_TEST_EXPECT(not fs.copyDirectory("copyDirectory", "COPY_copyDirectory"));
// Try copying again but now we ask to overwrite destination
SC_TEST_EXPECT(fs.copyDirectory("copyDirectory", "COPY_copyDirectory",
// Rename the directory (fs.rename works also for files)
SC_TEST_EXPECT(fs.rename("copyDirectory", "COPY_copyDirectory2"));
// Check that the directory has been renamed
SC_TEST_EXPECT(fs.existsAndIsDirectory("COPY_copyDirectory2"));
SC_TEST_EXPECT(not fs.existsAndIsDirectory("copyDirectory"));
// Rename the directory back to the original name
SC_TEST_EXPECT(fs.rename("COPY_copyDirectory2", "copyDirectory"));
// Remove all files created
SC_TEST_EXPECT(fs.removeFile("copyDirectory/testFile.txt"));
SC_TEST_EXPECT(fs.removeFile("copyDirectory/subdirectory/testFile.txt"));
SC_TEST_EXPECT(fs.removeEmptyDirectory("copyDirectory/subdirectory"));
SC_TEST_EXPECT(fs.removeEmptyDirectory("copyDirectory"));
// Remove the entire tree of directories for the copy
SC_TEST_EXPECT(fs.removeDirectoryRecursive("COPY_copyDirectory"));

Dependencies

Dependency Graph

Features

SC::FileSystem Execute fs operations { exists, copy, delete } for { files and directories }.
Copy Files
SC::FileSystem::copyFile Copy a single file.
Delete Files
SC::FileSystem::removeFile Remove a single file.
SC::FileSystem::removeFileIfExists Remove a single file, giving no error if it doesn't exist.
Copy Directories
SC::FileSystem::copyDirectory Copy a single directory.
Delete Directories
SC::FileSystem::removeEmptyDirectory Removes an empty directory.
SC::FileSystem::removeDirectoryRecursive Remove single directory with its entire content (like posix rm -rf)
Create Directories
SC::FileSystem::makeDirectory Creates a new directory that does not already exist.
SC::FileSystem::makeDirectoryIfNotExists Creates a new directory, if it doesn't already exists at the given path.
SC::FileSystem::makeDirectoryRecursive Create a new directory, creating also intermediate non existing directories (like posix mkdir -p)
Create Links
SC::FileSystem::createSymbolicLink Creates a symbolic link at location linkFile pointing at sourceFileOrDirectory.
SC::FileSystem::createHardLink Creates a hard link at location linkFile pointing at sourceFile.
Check Existence
SC::FileSystem::exists Check if a file or directory exists at a given path.
SC::FileSystem::existsAndIsFile Check if a file exists at given path.
SC::FileSystem::existsAndIsDirectory Check if a directory exists at given path.
SC::FileSystem::existsAndIsLink Check if a link exists at given path.
SC::FileSystem::canAccess Check whether the current process can access a path with the requested mode.
Rename files or directories
SC::FileSystem::rename Rename a file or directory.
Read / Change modification time
SC::FileSystem::stat Obtains richer metadata about a path, following symbolic links.
SC::FileSystem::lstat Obtains richer metadata about a path without following symbolic links.
SC::FileSystem::getFileStat Legacy convenience alias for stat(StringSpan, FileStat&)
SC::FileSystem::setLastModifiedTime Change last modified time of a given file.
SC::FileSystem::readSymbolicLink Reads the target path stored by a symbolic link.
SC::FileSystem::chmod Change file permission bits for a path, following symbolic links.
SC::FileSystem::chown Change owner and group for a path, following symbolic links.
SC::FileSystem::lchown Change owner and group for a path without following symbolic links.
SC::FileSystem::lchmod Change file permission bits for a symbolic link without following it.
Miscellaneous Classes
SC::FileSystem::Operations Low level filesystem API, requiring paths in native encoding (UTF-16 on Windows, UTF-8 elsewhere)
Get Executable / Application Path
SC::FileSystem::Operations::getExecutablePath

SC::FileSystem::Operations::getApplicationRootDirectory

Status

🟩 Usable
The library contains commonly used function including links, access checks and richer path metadata. Some lower level filesystem features are still missing, especially filesystem-level queries. SC::FileSystem::getFileTime and SC::FileSystem::setLastModifiedTime will probably be refactored in a future dedicated class for handling stat based operations.

Blog

Some relevant blog posts are:

Description

SC::FileSystem allows all typical file operations ( exists | copy | delete | make files or directory). Some less used functions are SC::FileSystem::getFileTime and SC::FileSystem::setLastModifiedTime . The library also supports symlink and hardlink creation, reading symlink targets and checking path accessibility. The library doesn't allow reading or writing seeking inside a file, as that is domain of the File library. SC::FileSystem::init needs an absolute path to a directory and makes it a the base directory. All paths passed later on as arguments to all methods can be either absolute paths or relative. If they are relative, they will be interpreted as relative to the base directory and NOT current directory of the process. The class wants explicitly to make sure its behavior doesn't implicitly depend on current directory of process (unless it's passed explicitly to SC::FileSystem::init of course).

Use SC::Path from Strings library to parse and compose paths.

FileSystem

copyFile

Copy a single file.

Parameters
sourceSource file path
destinationDestination file path
copyFlagsCopy flags (overwrite, use clone api etc.)
Returns
Valid Result if copy succeeded

Example:

// Make all operations relative to applicationRootDirectory
// Create a File names 'sourceFile.txt'
StringView contentSource = "this is some content";
SC_TEST_EXPECT(not fs.exists("sourceFile.txt"));
SC_TEST_EXPECT(fs.writeString("sourceFile.txt", contentSource));
// Check that 'sourceFile.txt' exist, but not 'destinationFile.txt'
SC_TEST_EXPECT(fs.existsAndIsFile("sourceFile.txt"));
SC_TEST_EXPECT(not fs.exists("destinationFile.txt"));
// Ask to copy sourceFile.txt to destinationFile.txt (eventually overwriting, but without cloning)
SC_TEST_EXPECT(fs.copyFile("sourceFile.txt", "destinationFile.txt",
// Now read the destinationFile.txt content and check if it's the same as source
String content = StringEncoding::Ascii;
SC_TEST_EXPECT(fs.read("destinationFile.txt", content));
SC_TEST_EXPECT(content.view() == contentSource);
// Copy again sourceFile.txt to destinationFile.txt but using clone this time
SC_TEST_EXPECT(fs.copyFile("sourceFile.txt", "destinationFile.txt",
// Check again if file exists and its content
SC_TEST_EXPECT(fs.existsAndIsFile("destinationFile.txt"));
SC_TEST_EXPECT(fs.read("destinationFile.txt", content));
SC_TEST_EXPECT(content.view() == contentSource);
// Remove all files created by the test
SC_TEST_EXPECT(fs.removeFiles({"sourceFile.txt", "destinationFile.txt"}));
SC_TEST_EXPECT(not fs.exists("sourceFile.txt"));
SC_TEST_EXPECT(not fs.exists("destinationFile.txt"));

copyDirectory

Copy a single directory.

Parameters
sourceSource directory path
destinationDestination directory path
copyFlagsCopy flags (overwrite, use clone api etc.)
Returns
Valid Result if copy succeeded

Example:

// Make all operations relative to applicationRootDirectory
// Create a nested directory structure with some files too
SC_TEST_EXPECT(fs.makeDirectory("copyDirectory"));
SC_TEST_EXPECT(fs.write("copyDirectory/testFile.txt", "asdf"));
SC_TEST_EXPECT(fs.existsAndIsFile("copyDirectory/testFile.txt"));
SC_TEST_EXPECT(fs.makeDirectory("copyDirectory/subdirectory"));
SC_TEST_EXPECT(fs.write("copyDirectory/subdirectory/testFile.txt", "asdf"));
// Copy the directory (recursively)
SC_TEST_EXPECT(fs.copyDirectory("copyDirectory", "COPY_copyDirectory"));
// Check that file exists in the new copied directory
SC_TEST_EXPECT(fs.existsAndIsFile("COPY_copyDirectory/testFile.txt"));
SC_TEST_EXPECT(fs.existsAndIsFile("COPY_copyDirectory/subdirectory/testFile.txt"));
// Copying again fails (because we're not overwriting)
SC_TEST_EXPECT(not fs.copyDirectory("copyDirectory", "COPY_copyDirectory"));
// Try copying again but now we ask to overwrite destination
SC_TEST_EXPECT(fs.copyDirectory("copyDirectory", "COPY_copyDirectory", FileSystem::CopyFlags().setOverwrite(true)));
// Remove all files created by the test
SC_TEST_EXPECT(fs.removeFile("copyDirectory/testFile.txt"));
SC_TEST_EXPECT(fs.removeFile("copyDirectory/subdirectory/testFile.txt"));
SC_TEST_EXPECT(fs.removeEmptyDirectory("copyDirectory/subdirectory"));
SC_TEST_EXPECT(fs.removeEmptyDirectory("copyDirectory"));
SC_TEST_EXPECT(fs.removeFile("COPY_copyDirectory/testFile.txt"));
SC_TEST_EXPECT(fs.removeFile("COPY_copyDirectory/subdirectory/testFile.txt"));
SC_TEST_EXPECT(fs.removeEmptyDirectory("COPY_copyDirectory/subdirectory"));
SC_TEST_EXPECT(fs.removeEmptyDirectory("COPY_copyDirectory"));

removeDirectoryRecursive

Remove single directory with its entire content (like posix rm -rf)

Parameters
directoryDirectory to remove
Returns
Valid Result if directory contents has been successfully deleted

Example:

// Make all operations relative to applicationRootDirectory
// Create a nested directory structure with some files too
SC_TEST_EXPECT(fs.makeDirectory("removeDirectoryTest"));
SC_TEST_EXPECT(fs.write("removeDirectoryTest/testFile.txt", "asdf"));
SC_TEST_EXPECT(fs.makeDirectory("removeDirectoryTest/another"));
SC_TEST_EXPECT(fs.write("removeDirectoryTest/another/yeah.txt", "asdf"));
// Remove the entire tree of directories
SC_TEST_EXPECT(fs.removeDirectoryRecursive("removeDirectoryTest"));
// Check that all files and directories have been removed
SC_TEST_EXPECT(not fs.existsAndIsFile("removeDirectoryTest/testFile.txt"));
SC_TEST_EXPECT(not fs.existsAndIsFile("removeDirectoryTest/another/yeah.txt"));
SC_TEST_EXPECT(not fs.existsAndIsDirectory("removeDirectoryTest/another"));
SC_TEST_EXPECT(not fs.existsAndIsDirectory("removeDirectoryTest"));

makeDirectoryRecursive

Create a new directory, creating also intermediate non existing directories (like posix mkdir -p)

Parameters
directoryPath where to create such directory
Returns
Invalid Result in case of I/O or access error
// Make all operations relative to applicationRootDirectory
// Create a directory with 2 levels of nesting
// Check that both levels have been created
SC_TEST_EXPECT(fs.existsAndIsDirectory("Test3/Subdir"));
// Remove both levels of directory
SC_TEST_EXPECT(fs.removeEmptyDirectory("Test3/Subdir"));

existsAndIsFile

Check if a file exists at given path.

Parameters
fileFile path to check
Returns
true if a file exists at the given path

Example:

// Make all operations relative to applicationRootDirectory
// Create a File names 'sourceFile.txt'
StringView contentSource = "this is some content";
SC_TEST_EXPECT(not fs.exists("sourceFile.txt"));
SC_TEST_EXPECT(fs.writeString("sourceFile.txt", contentSource));
// Check that 'sourceFile.txt' exist, but not 'destinationFile.txt'
SC_TEST_EXPECT(fs.existsAndIsFile("sourceFile.txt"));
SC_TEST_EXPECT(not fs.exists("destinationFile.txt"));
// Ask to copy sourceFile.txt to destinationFile.txt (eventually overwriting, but without cloning)
SC_TEST_EXPECT(fs.copyFile("sourceFile.txt", "destinationFile.txt",
// Now read the destinationFile.txt content and check if it's the same as source
String content = StringEncoding::Ascii;
SC_TEST_EXPECT(fs.read("destinationFile.txt", content));
SC_TEST_EXPECT(content.view() == contentSource);
// Copy again sourceFile.txt to destinationFile.txt but using clone this time
SC_TEST_EXPECT(fs.copyFile("sourceFile.txt", "destinationFile.txt",
// Check again if file exists and its content
SC_TEST_EXPECT(fs.existsAndIsFile("destinationFile.txt"));
SC_TEST_EXPECT(fs.read("destinationFile.txt", content));
SC_TEST_EXPECT(content.view() == contentSource);
// Remove all files created by the test
SC_TEST_EXPECT(fs.removeFiles({"sourceFile.txt", "destinationFile.txt"}));
SC_TEST_EXPECT(not fs.exists("sourceFile.txt"));
SC_TEST_EXPECT(not fs.exists("destinationFile.txt"));

existsAndIsDirectory

Check if a directory exists at given path.

Parameters
directoryDirectory path to check
Returns
true if a directory exists at the given path

rename

Rename a file or directory.

Parameters
pathThe path to the file or directory to rename
newPathThe new path to the file or directory
Returns
Valid Result if the file or directory was renamed

Example:

// Create a file and check that it exists
SC_TEST_EXPECT(fs.writeString("renameTest.txt", "asdf"));
SC_TEST_EXPECT(fs.existsAndIsFile("renameTest.txt"));
// Rename the file
SC_TEST_EXPECT(fs.rename("renameTest.txt", "renameTest2.txt"));
// Check that the file has been renamed
SC_TEST_EXPECT(fs.existsAndIsFile("renameTest2.txt"));
SC_TEST_EXPECT(not fs.existsAndIsFile("renameTest.txt"));
// Rename the file again
SC_TEST_EXPECT(fs.rename("renameTest2.txt", "renameTest.txt"));
// Check that the file has been renamed
SC_TEST_EXPECT(fs.existsAndIsFile("renameTest.txt"));
SC_TEST_EXPECT(not fs.existsAndIsFile("renameTest2.txt"));
// Remove all files created by the test
SC_TEST_EXPECT(fs.removeFile("renameTest.txt"));
// Create a directory and check that it exists
SC_TEST_EXPECT(fs.makeDirectory("renameDirectoryTest"));
SC_TEST_EXPECT(fs.existsAndIsDirectory("renameDirectoryTest"));
// Create a file in the directory
SC_TEST_EXPECT(fs.writeString("renameDirectoryTest/testFile.txt", "asdf"));
SC_TEST_EXPECT(fs.existsAndIsFile("renameDirectoryTest/testFile.txt"));
// Create a subdirectory in the directory
SC_TEST_EXPECT(fs.makeDirectory("renameDirectoryTest/subdirectory"));
SC_TEST_EXPECT(fs.existsAndIsDirectory("renameDirectoryTest/subdirectory"));
// Create a file in the subdirectory
SC_TEST_EXPECT(fs.writeString("renameDirectoryTest/subdirectory/testFile.txt", "asdf"));
SC_TEST_EXPECT(fs.existsAndIsFile("renameDirectoryTest/subdirectory/testFile.txt"));
// Rename the directory
SC_TEST_EXPECT(fs.rename("renameDirectoryTest", "renameDirectoryTest2"));
// Check that the directory has been renamed
SC_TEST_EXPECT(fs.existsAndIsDirectory("renameDirectoryTest2"));
SC_TEST_EXPECT(not fs.existsAndIsDirectory("renameDirectoryTest"));
// Check that the file in the directory has been renamed
SC_TEST_EXPECT(fs.existsAndIsFile("renameDirectoryTest2/testFile.txt"));
SC_TEST_EXPECT(not fs.existsAndIsFile("renameDirectoryTest/testFile.txt"));
// Check that the file in the subdirectory has been renamed
SC_TEST_EXPECT(fs.existsAndIsFile("renameDirectoryTest2/subdirectory/testFile.txt"));
SC_TEST_EXPECT(not fs.existsAndIsFile("renameDirectoryTest/subdirectory/testFile.txt"));
// Remove all directories created by the test
SC_TEST_EXPECT(fs.removeDirectoryRecursive("renameDirectoryTest2"));

createSymbolicLink

Creates a symbolic link at location linkFile pointing at sourceFileOrDirectory.

Parameters
sourceFileOrDirectoryThe target of the link (can be a folder or directory)
linkFileThe location where the symbolic link will be created
Returns
Invalid result if it's not possible creating the requested symbolic link

createHardLink

Creates a hard link at location linkFile pointing at sourceFile.

Parameters
sourceFileThe target file of the hard link
linkFileThe location where the hard link will be created
Returns
Invalid result if it's not possible creating the requested hard link

existsAndIsLink

Check if a link exists at given path.

Parameters
fileLink path to check
Returns
true if a file exists at the given path

canAccess

Check whether the current process can access a path with the requested mode.

Parameters
fileOrDirectoryPath to check
accessModeRequested access mode
Returns
true if the requested access is allowed

stat

Obtains richer metadata about a path, following symbolic links.

Parameters
filePath to the file of interest
[out]fileStatDestination structure that will receive statistics about the file
Returns
Valid Result if file stats for the given file was successfully read

lstat

Obtains richer metadata about a path without following symbolic links.

Parameters
filePath to the file of interest
[out]fileStatDestination structure that will receive statistics about the file
Returns
Valid Result if file stats for the given file was successfully read

readSymbolicLink

Reads the target path stored by a symbolic link.

Parameters
linkFilePath to the symbolic link
[out]destinationDestination receiving the native-encoded target path
Returns
Valid Result if link target was successfully read

chmod

Change file permission bits for a path, following symbolic links.

Parameters
pathPath to the file or directory of interest
modePlatform-native numeric mode bits
Returns
Valid Result if permissions were updated successfully

chown

Change owner and group for a path, following symbolic links.

Parameters
pathPath to the file or directory of interest
uidPlatform-native numeric owner identifier
gidPlatform-native numeric group identifier
Returns
Valid Result if ownership was updated successfully

lchown

Change owner and group for a path without following symbolic links.

Parameters
pathPath to the file or directory of interest
uidPlatform-native numeric owner identifier
gidPlatform-native numeric group identifier
Returns
Valid Result if ownership was updated successfully

lchmod

Change file permission bits for a symbolic link without following it.

Parameters
pathPath to the symbolic link of interest
modePlatform-native numeric mode bits
Returns
Valid Result if permissions were updated successfully

write

Writes a block of memory to a file.

Parameters
filePath to the file that is meant to be written
dataBlock of memory to write
Returns
Valid Result if the memory was successfully written

Example:

// Make all operations relative to applicationRootDirectory
StringView content = "ASDF content";
// Check that file doesn't exists before write-ing it and then check that it exist
SC_TEST_EXPECT(not fs.exists("file.txt"));
SC_TEST_EXPECT(fs.writeString("file.txt", content));
// Read the file and check its content
String newString = StringEncoding::Ascii;
SC_TEST_EXPECT(fs.read("file.txt", newString));
SC_TEST_EXPECT(newString.view() == content);
// Remove all files created by the test
SC_TEST_EXPECT(fs.removeFile("file.txt"));
SC_TEST_EXPECT(not fs.exists("file.txt"));

read

Read contents of a file into a String or Buffer.

Parameters
[in]filePath to the file to read
[out]dataDestination String or Buffer that will receive file contents
Returns
Valid Result if the entire file has been read successfully
See also
write (for an usage example)

Roadmap

🟦 Complete Features:

  • statfs

Statistics

Type Lines Of Code Comments Sum
Headers 117 232 349
Sources 1408 230 1638
Sum 1525 462 1987