lfilesystem  0.0.1
C++ filesystem library
limes_files

The Limes filesystem library. More...

+ Collaboration diagram for limes_files:

Modules

 Special directories
 Utility functions for finding some common directory locations.
 

Files

file  lfilesystem.h
 The main header for the limes_files library.
 
file  lfilesystem_CFile.h
 This file defines the CFile class.
 
file  lfilesystem_Directory.h
 This file defines the Directory class.
 
file  lfilesystem_DynamicLibrary.h
 This file defines the DynamicLibrary class.
 
file  lfilesystem_File.h
 This file defines the File and TempFile classes.
 
file  lfilesystem_FilesystemEntry.h
 This file defines the FilesystemEntry class.
 
file  lfilesystem_FileWatcher.h
 This file defines the files::FileWatcher class.
 
file  lfilesystem_Misc.h
 This file defines miscellaneous filesystem utility functions.
 
file  lfilesystem_Paths.h
 This file defines some utility functions for working with paths.
 
file  lfilesystem_Permissions.h
 This file defines the Permissions class.
 
file  lfilesystem_SimpleWatcher.h
 This file defines the SimpleFileWatcher class.
 
 
file  lfilesystem_Volume.h
 This file defines the files::Volume class.
 

Typedefs

using limes::files::FSPerms = std::filesystem::perms
 A typedef for the standard library permissions type. More...
 
using limes::files::Path = std::filesystem::path
 Convenience typedef for filesystem paths. More...
 

Functions

LFILE_EXPORT bool limes::files::isValidPath (const Path &path)
 Tests whether the passed path contains any invalid characters or character sequences, such as :: . More...
 
LFILE_EXPORT Path limes::files::largestCommonPrefix (const Path &path1, const Path &path2)
 Returns the largest prefix path fragment common to path1 and path2 . More...
 
LFILE_EXPORT Path limes::files::normalizePath (const Path &path)
 This function takes an input path and does some linting and transformations to create a consistent, canonical form of the path. More...
 
std::ostream & operator<< (std::ostream &os, const File &file)
 Writes the file's contents to the output stream. More...
 
std::ostream & operator<< (std::ostream &os, const FilesystemEntry &value)
 Writes a FilesystemEntry's path to the output stream. More...
 
std::ostream & operator<< (std::ostream &os, const Permissions &value)
 Writes a Permissions object's string representation to the output stream. More...
 
std::ostream & operator<< (std::ostream &os, const Volume &value)
 Writes the Volume object's path to the output stream. More...
 
std::istream & operator>> (std::istream &is, const File &file)
 Reads content from the input stream, and overwrites the file with it. More...
 
constexpr LFILE_EXPORT char limes::files::dirSeparator () noexcept
 Returns the platform's preferred directory separator: \ on Windows, and / everywhere else. More...
 
LFILE_EXPORT consteval char limes::files::PATHseparator () noexcept
 Returns the platform's separator char for the PATH environment variable: ; on Windows, and : everywhere else. More...
 
LFILE_EXPORT consteval bool limes::files::filesystemIsCaseSensitive () noexcept
 Returns true if the current platform's filesystem is likely to be case-sensitive. More...
 
constexpr LFILE_EXPORT std::uintmax_t limes::files::maxPathLength () noexcept
 Returns the maximum path length possible on the current operating system. More...
 

Detailed Description

The Limes filesystem library.

Overview

All classes and functions in this library are accessible after linking to the limes::lfilesystem library and including lfilesystem.h.

This library provides utilities for working with the filesystem from a high-level, object-oriented point of view.

Design goals

Limes's filesystem library is built on top of the std::filesystem library, but I've preferred a more strongly object oriented design over free functions.

I wanted a strongly-typed interface for working with filesystem objects, primarily to differentiate between files and directories. You can still construct paths that wouldn't be considered canonical for a given filesystem object type – for instance, the Directory class won't prevent you from creating one referencing /usr/documents/a_file.txt – but I believe that having strongly-typed classes for each kind of filesystem object provides a cleaner API and allows the programmer to more explicitly express their intent.

If a feature is available in the standard library, I've preferred to use the standard library functions rather than platform-specific code wherever possible. If the standard expands to include features currently implemented with custom low-level platform code (such as the Volume class), then this library will be refactored to use the standard library code, as soon as that code is available on all platforms and compilers targeted by Limes.

Another design principle of this library is that most operations are noexcept – success or failure is usually indicated by a boolean return value, or a null optional. Exceptions are only thrown when the library cannot continue in a reasonable state – such as in the constructor of the Volume class, if the volume for a certain path cannot be determined.

Features

The main entry points to this library are the File, Directory and SymLink classes. Volume is also a top-level class. All of these classes simply hold a path and have methods for manipulating it or interacting with the filesystem using this path – none of these classes hold data or significant resources other than the path itself, so they can be freely copied around, or relatively quickly constructed and destroyed.

This library's design also allows more custom filesystem object types to be added in the future – you can inherit from FilesystemEntry and create your own kinds of file-like objects that will work with Directory::iterateAllChildren() and the rest of this library's API.

The FileWatcher class is another key feature of this library: you can create an object to receive callbacks when a file or directory is modified.

Portability

All features are designed to work as similarly across all platforms as possible. However, on Windows, paths containing backslashes are valid. Windows also recognizes Unix-style paths – so Unix-style paths are valid on all platforms, but Windows also works with Windows-style paths.

If certain features are not supported on all platforms (such as DynamicLibrary or FileWatcher ), functions are provided to check if the current system supports the feature.

Examples

Here is some example code that demonstrates some of this library's features:

This code listens to changes to a directory and maintains a list of all JSON files in the directory:

/*
* ======================================================================================
* __ ____ __ __ ____ ___
* ( ) (_ _)( \/ )( ___)/ __)
* )(__ _)(_ ) ( )__) \__ \
* (____)(____)(_/\/\_)(____)(___/
*
* This file is part of the Limes open source library and is licensed under the terms of the GNU Public License.
*
* Commercial licenses are available; contact the maintainers at ben.the.vining@gmail.com to inquire for details.
*
* ======================================================================================
*/
#include <vector>
{
explicit JSONWatcher (const limes::files::Directory& dir)
: limes::files::FileWatcher (dir), directory (dir)
{ }
std::vector<limes::files::File> jsonFiles;
const limes::files::Directory directory;
void fileCreated (const limes::files::FilesystemEntry& file) final
{
if (! directory.contains (file))
return;
if (const auto fileObj = file.getFileObject())
{
if (fileObj->hasFileExtension (".json"))
jsonFiles.emplace_back (*fileObj);
}
}
void fileDeleted (const limes::files::FilesystemEntry& file) final
{
jsonFiles.erase (std::find_if (jsonFiles.begin(), jsonFiles.end(),
[p = file.getAbsolutePath()] (limes::files::File& f)
{
return f.getAbsolutePath() == p;
}));
}
void fileMoved (const limes::files::FilesystemEntry& file) final
{
if (! directory.contains (file))
{
fileDeleted (file);
return;
}
if (const auto fileObj = file.getFileObject())
{
if (! fileObj->hasFileExtension (".json"))
return;
const auto alreadyInList = (std::find (jsonFiles.begin(),
jsonFiles.end(),
*fileObj)
!= jsonFiles.end());
if (! alreadyInList)
jsonFiles.emplace_back (*fileObj);
}
}
};
const limes::files::Directory dir { "/my/directory" };
JSONWatcher watcher { dir };
This class represents a directory on the filesystem.
bool contains(const FilesystemEntry &entry, std::size_t depthLimit=50) const
Returns true if this directory contains the passed FilesystemEntry.
This class listens for changes to or operations on a certain file, and receives callbacks to be notif...
FileWatcher() noexcept
Creates an inactive FileWatcher that does nothing.
This class represents a file on the filesystem.
The base class for any kind of object on the filesystem.
The main header for the limes_files library.
void fileDeleted(const limes::files::FilesystemEntry &file) final
Called when a file is deleted.
void fileCreated(const limes::files::FilesystemEntry &file) final
Called when a file or subdirectory is created in a watched directory.
void fileMoved(const limes::files::FilesystemEntry &file) final
Called when a file is moved or renamed.

This code reads all the files in the current working directory, prints them line by line, concatenates all the output and prints the combined data to a new file:

/*
* ======================================================================================
* __ ____ __ __ ____ ___
* ( ) (_ _)( \/ )( ___)/ __)
* )(__ _)(_ ) ( )__) \__ \
* (____)(____)(_/\/\_)(____)(___/
*
* This file is part of the Limes open source library and is licensed under the terms of the GNU Public License.
*
* Commercial licenses are available; contact the maintainers at ben.the.vining@gmail.com to inquire for details.
*
* ======================================================================================
*/
#include <sstream>
#include <iostream>
void iterate_directory()
{
const auto dir = limes::files::dirs::cwd();
std::stringstream stream;
dir.iterateFiles ([&stream] (const limes::files::File& f)
{
for (const auto& line : f.loadAsLines())
{
std::cout << line << std::endl;
stream << line;
} });
const auto newFile = dir.getChildFile ("concat.txt");
newFile.overwrite (stream.str());
}
void iterateFiles(FileCallback &&callback, bool recurse=true, bool includeHiddenFiles=true) const
Calls a function for each child file that exists in this directory.
File getChildFile(const std::string_view &filename, bool createIfNeeded=false) const
Returns a File object representing a file in this directory with the specified name.
std::vector< std::string > loadAsLines() const
Loads the file's contents as a vector of strings, with each string containing the contents of one lin...
bool overwrite(const char *const data, std::size_t numBytes) const noexcept
Replaces the file's contents with the given data.
Todo:
FileSearchPath class and/or glob() function
Todo:
MemoryMappedFile class
Todo:
Android support
Todo:
CLI app
Todo:
remove internal dependencies on exceptions (Emscripten tests)
Todo:
get all CI builds working

Typedef Documentation

◆ FSPerms

using limes::files::FSPerms = typedef std::filesystem::perms

A typedef for the standard library permissions type.

Definition at line 34 of file lfilesystem_Permissions.h.

◆ Path

typedef std::filesystem::path limes::files::Path

Convenience typedef for filesystem paths.

Definition at line 43 of file lfilesystem_FilesystemEntry.h.

Function Documentation

◆ dirSeparator()

constexpr LFILE_EXPORT char limes::files::dirSeparator ( )
constexprnoexcept

Returns the platform's preferred directory separator: \ on Windows, and / everywhere else.

Definition at line 43 of file lfilesystem_Misc.h.

◆ filesystemIsCaseSensitive()

LFILE_EXPORT consteval bool limes::files::filesystemIsCaseSensitive ( )
noexcept

Returns true if the current platform's filesystem is likely to be case-sensitive.

This is a compile-time determination based on platform conventions – this function returns true on Linux, and false everywhere else. For a more accurate runtime query of the actual filesystem, see Volume::isCaseSensitive() and volume::caseSensitive().

See also
volume::caseSensitive(), Volume::isCaseSensitive()

Definition at line 69 of file lfilesystem_Misc.h.

◆ isValidPath()

LFILE_EXPORT bool limes::files::isValidPath ( const Path path)

Tests whether the passed path contains any invalid characters or character sequences, such as :: .

This also returns false if the path is longer than maxPathLength() . This returns false if the passed path is empty.

See also
normalizePath()

◆ largestCommonPrefix()

LFILE_EXPORT Path limes::files::largestCommonPrefix ( const Path path1,
const Path path2 
)

Returns the largest prefix path fragment common to path1 and path2 .

For example, if path1 is a/b/c/d and path2 is a/b/e/f then this will return a/b . Both paths will be normalized via normalizePath() before computing the common prefix.

◆ maxPathLength()

constexpr LFILE_EXPORT std::uintmax_t limes::files::maxPathLength ( )
constexprnoexcept

Returns the maximum path length possible on the current operating system.

This is a compile-time constant defined by platform headers.

Todo:
query the actual underlying filesystem for this?

Definition at line 83 of file lfilesystem_Misc.h.

◆ normalizePath()

LFILE_EXPORT Path limes::files::normalizePath ( const Path path)

This function takes an input path and does some linting and transformations to create a consistent, canonical form of the path.

If isValidPath() returns false for the input path, this function returns an empty path.

Any trailing directory separators will be removed. Path segments of the form /./ will be normalized to / . This is also true of .. – a path of the form some/rel/../path will be normalized to some/path .

On non-Windows platforms, a tilde in the path will be expanded to the home directory, and paths of the form ~username will be expanded to the user username 's home directory.

See also
isValidPath()

◆ operator<<() [1/4]

std::ostream & operator<< ( std::ostream &  os,
const File file 
)
related

Writes the file's contents to the output stream.

◆ operator<<() [2/4]

std::ostream & operator<< ( std::ostream &  os,
const FilesystemEntry value 
)
related

Writes a FilesystemEntry's path to the output stream.

◆ operator<<() [3/4]

std::ostream & operator<< ( std::ostream &  os,
const Permissions value 
)
related

Writes a Permissions object's string representation to the output stream.

◆ operator<<() [4/4]

std::ostream & operator<< ( std::ostream &  os,
const Volume value 
)
related

Writes the Volume object's path to the output stream.

◆ operator>>()

std::istream & operator>> ( std::istream &  is,
const File file 
)
related

Reads content from the input stream, and overwrites the file with it.

◆ PATHseparator()

LFILE_EXPORT consteval char limes::files::PATHseparator ( )
noexcept

Returns the platform's separator char for the PATH environment variable: ; on Windows, and : everywhere else.

Todo:
is there a way to actually query the underlying filesystem for this?

Definition at line 52 of file lfilesystem_Misc.h.