{"id":13436692,"url":"https://github.com/cginternals/cppfs","last_synced_at":"2025-04-04T13:12:44.591Z","repository":{"id":19429161,"uuid":"87018368","full_name":"cginternals/cppfs","owner":"cginternals","description":"Cross-platform C++ file system library supporting multiple backends","archived":false,"fork":false,"pushed_at":"2024-07-25T17:29:10.000Z","size":1927,"stargazers_count":479,"open_issues_count":14,"forks_count":73,"subscribers_count":30,"default_branch":"master","last_synced_at":"2025-03-28T12:07:50.405Z","etag":null,"topics":["c-plus-plus","c-plus-plus-11","filesystem-library","library"],"latest_commit_sha":null,"homepage":null,"language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cginternals.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":"AUTHORS","dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-04-02T21:47:31.000Z","updated_at":"2025-03-08T11:24:38.000Z","dependencies_parsed_at":"2022-07-27T00:32:05.057Z","dependency_job_id":"c13d6d07-1117-40d3-836b-ca5e371c46fa","html_url":"https://github.com/cginternals/cppfs","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cginternals%2Fcppfs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cginternals%2Fcppfs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cginternals%2Fcppfs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cginternals%2Fcppfs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cginternals","download_url":"https://codeload.github.com/cginternals/cppfs/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247182365,"owners_count":20897380,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["c-plus-plus","c-plus-plus-11","filesystem-library","library"],"created_at":"2024-07-31T03:00:51.327Z","updated_at":"2025-04-04T13:12:44.575Z","avatar_url":"https://github.com/cginternals.png","language":"C++","readme":"[//]: # (Comment)\n\n\u003cbr\u003e\u003ca href=\"https://github.com/cginternals/cppfs/\"\u003e\u003cimg src=\"https://raw.githubusercontent.com/cginternals/cppfs/master/cppfs-logo.svg?sanitize=true\" width=\"50%\"\u003e\u003c/a\u003e\n\n*cppfs* is a cross-platform C++ library that provides an object-oriented abstraction for working with files and the file system. \n\n![GitHub release](https://img.shields.io/github/release/cginternals/cppfs.svg) \n[![Travis](https://img.shields.io/travis/cginternals/cppfs/master.svg?style=flat\u0026logo=travis)](https://travis-ci.org/cginternals/cppfs)\n[![Appveyor](https://img.shields.io/appveyor/ci/scheibel/cppfs/master.svg?style=flat\u0026logo=appveyor)](https://ci.appveyor.com/project/scheibel/cppfs/branch/master)\n[![Tokei](https://tokei.rs/b1/github/cginternals/cppfs)](https://github.com/Aaronepower/tokei)\n[![Tokei](https://tokei.rs/b1/github/cginternals/cppfs?category=comments)](https://github.com/Aaronepower/tokei)\n\n*cppfs* can be used not only to access the local file system, but for remote and virtual file systems as well.\nBy specializing the virtual backend interface, *cppfs* can be easily extended to support additional\nremote protocols or virtual file systems.\nThe following backends are currently implemented:\n- Local file system (POSIX, win32)\n- SSH (libssh2)\n\n\n# Resources\n\n* [Basic Examples](#basic-examples)\n\n##### Installation and Development\n\n* [Build form Source](#build-instructions)\n* [Tips for Linking](#tips-for-linking)\n\n##### Features\n * [Paths and URLs](#paths-and-urls)\n * [Accessing the file system](#accessing-the-file-system)\n * [Getting file information](#getting-file-information)\n * [File operations](#file-operations)\n * [Reading and writing to files](#reading-and-writing-to-files)\n * [Advanced functions on files](#advanced-functions-on-files)\n * [Accessing and traversing directories](#accessing-and-traversing-directories)\n * [File trees and diffs](#file-trees-and-diffs)\n\n\n# Build Instructions\n\nPlease follow our [CMake project setup guide](https://github.com/cginternals/cmake-init/wiki/Setup-Guide)\nto setup and build *cppfs*.\n\n\n# Basic Examples\n\nOpening files and checking for existence and type:\n\n```C++\n#include \u003ccppfs/fs.h\u003e\n#include \u003ccppfs/FileHandle.h\u003e\n\nusing namespace cppfs;\n\nvoid openFile(const std::string \u0026 filename)\n{\n    FileHandle fh = fs::open(filename);\n\n         if (fh.isFile())      { /* File ... */ }\n    else if (fh.isDirectory()) { /* Directory ... */ }\n    else if (!fh.exists())     { /* Not there ... */ }\n}\n```\n\nOpen a file for reading or writing:\n\n```C++\n#include \u003ccppfs/fs.h\u003e\n#include \u003ccppfs/FileHandle.h\u003e\n\nusing namespace cppfs;\n\nvoid openFile(const std::string \u0026 filename)\n{\n    FileHandle fh = fs::open(filename);\n\n    if (fh.isFile())\n    {\n        auto in = fh.createInputStream();\n        // ...\n\n        auto out = fh.createOutputStream();\n        // ...\n    }\n}\n```\n\nListing directory entries:\n\n```C++\n#include \u003ccppfs/fs.h\u003e\n#include \u003ccppfs/FileHandle.h\u003e\n\nusing namespace cppfs;\n\nvoid lstDir(const std::string \u0026 path)\n{\n    FileHandle dir = fs::open(path);\n\n    if (dir.isDirectory())\n    {\n        for (FileIterator it = dir.begin(); it != dir.end(); ++it)\n        {\n            std::string path = *it;\n        }\n    }\n}\n```\n\n\n# Features\n\n### Paths and URLs\n\nThe class *FilePath* is used to represent paths in the file system.\nIt can be constructed from a string and converted back into a string.\n\n```C++\nFilePath path(\"data/readme.txt\");\nstd::string pathOut = path.path();\n```\n\nPaths are stored in a unified format using only forward slashes ('/')\nas a separator. The unified format is compatible to all systems,\nbut as a convenience for the user, it should be converted to the\nnative format when displaying paths. To convert a path into the native\nformat, call *toNative*.\n\n```C++\nFilePath path(\"data/readme.txt\");\nstd::cout \u003c\u003c \"File path: \" \u003c\u003c path.toNative() \u003c\u003c std::endl;\n```\n\nA *FilePath* can be used to obtain syntactical information about a path.\nIt does however work purely on the string, it cannot provide information\nabout the actual file or directory the path points to. The following\nfunctions are useful to get information about a path:\n\n```C++\nFilePath path = ...;\n\n// Check if the path is empty (\"\")\nbool empty = path.isEmpty();\n\n// Check if the path is an absolute path (e.g., \"/test.txt\", or \"C:/test.txt\")\nbool abs = path.isAbsolute();\n\n// Check if the path is a relative path (e.g., \"data/test.txt\")\nbool rel = path.isRelative();\n\n// Check if path points to a file/directory (e.g., \"/path/to/dir\")\n// or its content (e.g., \"/path/to/dir/\").\nbool listContent = path.pointsToContent();\n```\n\n*FilePath* offers functions to obtain the individual components of a file path,\nsuch as the filename, extension, or path to the containing directory.\nAll of these functions ignore trailing slashes on the path, so they operate on\nthe object the path points to, not it contents.\n\n```C++\nFilePath path1(\"C:/path/to/file.txt\");\nFilePath path2(\"C:/path/to/directory/\");\n\n// Get full path\nstd::cout \u003c\u003c path1.fullPath() \u003c\u003c std::endl; // \"C:/path/to/file.txt\"\nstd::cout \u003c\u003c path2.fullPath() \u003c\u003c std::endl; // \"C:/path/to/directory\"\n\n// Get filename components\nstd::cout \u003c\u003c path1.fileName()  \u003c\u003c std::endl; // \"file.txt\"\nstd::cout \u003c\u003c path2.fileName()  \u003c\u003c std::endl; // \"directory\"\nstd::cout \u003c\u003c path1.baseName()  \u003c\u003c std::endl; // \"file\"\nstd::cout \u003c\u003c path2.baseName()  \u003c\u003c std::endl; // \"directory\"\nstd::cout \u003c\u003c path1.extension() \u003c\u003c std::endl; // \".txt\"\nstd::cout \u003c\u003c path2.extension() \u003c\u003c std::endl; // \"\"\n\n// Get path to containing directory\nstd::cout \u003c\u003c path1.directoryPath() \u003c\u003c std::endl; // \"C:/path/to/\"\nstd::cout \u003c\u003c path2.directoryPath() \u003c\u003c std::endl; // \"C:/path/to/\"\n\n// Get drive letter\nstd::cout \u003c\u003c path1.driveLetter() \u003c\u003c std::endl; // \"C:\"\nstd::cout \u003c\u003c path2.driveLetter() \u003c\u003c std::endl; // \"C:\"\n```\n\nPaths often need to be combined in order to determine the actual location\nof a file. To combine two paths, the function *resolve* can be used. The\nsecond path must be relative to combine the two paths, otherwise only the\nsecond path is returned. The combination of paths also takes place on\na pure syntactical level, without checking if any of the paths really exist.\n\n```C++\nFilePath src(\"C:/projects\");\nFilePath rel(\"../documents/test.txt\");\nFilePath abs(\"C:/projects2/readme.txt\");\n\nFilePath path1 = src.resolve(rel);\nstd::cout \u003c\u003c path1.fullPath() \u003c\u003c std::endl; // \"C:/projects/../documents/test.txt\"\n\nFilePath path2 = src.resolve(abs);\nstd::cout \u003c\u003c path2.fullPath() \u003c\u003c std::endl; // \"C:/projects2/readme.txt\"\n```\n\nWhen combining relative paths, the resulting strings may contain a lot\nof \"..\" and \".\" components. To resolve these on a syntactical level, the\nfunction *resolved* can be called. It will remove all occurences of \".\"\nand \"..\", as long as it is possible. Occurences of \"..\" at the beginning\nof a path will not be removed.\n\n```C++\nFilePath path(\"C:/projects/../documents/test.txt\");\nstd::cout \u003c\u003c path.resolved() \u003c\u003c std::endl; // \"C:/documents/test.txt\"\n```\n\n\n### Accessing the file system\n\nThe main class for accessing files and directories in cppfs is *FileHandle*.\nIt can be used to get information about file system objects, to manipulate\nthem (e.g., copy, rename, or delete), as well as to read and write files.\n\nTo obtain a file handle, the global function *fs::open* can be called. The\ntype of file system that is accessed will be determined automatically by the\ngiven path or URL. File systems will be closed automatically when there are\nno longer any open file handles left.\n\n```C++\n// Open local file\nFileHandle file1 = fs::open(\"data/readme.txt\");\n\n// Open file on SSH server\nLoginCredentials login;\nlogin.setValue(\"username\",   \"username\");\nlogin.setValue(\"password\",   \"password\");\nlogin.setValue(\"publicKey\",  \"/path/to/key.pub\"); // Default: \"$home/.ssh/id_rsa.pub\"\nlogin.setValue(\"privateKey\", \"/path/to/key\");     // Default: \"$home/.ssh/id_rsa\"\nlogin.setValue(\"port\",       \"999\");              // Default: 22\n\nFileHandle file2 = fs::open(\"ssh://example.com/home/user/readme.txt\", \u0026login);\n```\n\nAt the moment, it is not possible to register new file systems at the global\nlevel. To use a custom file system, create an instance of it and use the\n*AbstractFileSystem* interface to access it.\n\n```C++\nclass CustomFS : public AbstractFileSystem\n{\n    ...\n};\n\nCustomFS fs;\nFileHandle file = fs.open(\"data/readme.txt\");\n```\n\n\n### Getting file information\n\nA file handle can be used to access information about the file\nsystem object it points to. A file handle can also be copied,\ncreating a second handle that points to the same file system\nobject but does not inherit the state of the former handle.\nThis operation only copies the path of the handle to the\nnew object, so it is a cheap operation.\n\n```C++\n// Open file from local file system\nFileHandle file = fs::open(\"data/readme.txt\");\n\n// Get a second handle to the same file\nFileHandle file2 = file;\n```\n\nOnce a file handle has been obtained, it can be used to query basic information\nabout the file system object is points to.\n\n```C++\nFileHandle file = fs::open(\"data/readme.txt\");\n\n// Check type\n     if (file.isFile())         std::cout \u003c\u003c \"file\" \u003c\u003c std::endl;\nelse if (file.isDirectory())    std::cout \u003c\u003c \"directory\" \u003c\u003c std::endl;\nelse if (file.isSymbolicLink()) std::cout \u003c\u003c \"symlink\" \u003c\u003c std::endl;\nelse if (!file.exists())        std::cout \u003c\u003c \"file does not exist\" \u003c\u003c std::endl;\n\n// Get filename and path\nstd::string path = file.path();\nstd::string filename = file.fileName();\n\n// Get file information\nunsigned int  size  = file.size();\nunsigned int  atime = file.accessTime();\nunsigned int  mtime = file.modificationTime();\nunsigned int  uid   = file.userId();\nunsigned int  gid   = file.groupId();\nunsigned long perm  = file.permissions();\n```\n\nFile permissions can also be modified:\n\n```C++\nFileHandle file = fs::open(\"data/readme.txt\");\n\nfile.setUserId(1000);\nfile.setGroupId(1000);\nfile.setPermissions(FilePermissions::UserRead | FilePermissions::GroupRead);\n```\n\nThe file information is retrieved only when needed, i.e., on the first call\nof one of the above functions, and then cached in memory. When an operation on\nthe handle modifies the file information, it is updated automatically.\nHowever, if a file is modified outside of the application or using a different\nhandle to the same file, the file handle cannot know about the change. Therefore,\nit must be updated manually:\n\n```C++\nFileHandle file = fs::open(\"data/readme.txt\");\n\n// If the file has been modified outside the application ...\nfile.updateFileInfo();\n```\n\n\n### File operations\n\nUsing the *FileHandle*, basic file operations can be performed.\nFor binary operations, such as copy or move, the second file handle\nis considered to be the target of the operation. Depending on the\noperation, the target does not need to already exist. If the target\npoints to a directory rather than a file, the target will be considered\nto be inside that directory (for example, a file will be copied into\nthe given directory).\n\n```C++\nFileHandle dir  = fs::open(\"data\");\nFileHandle file = fs::open(\"readme.txt\");\nFileHandle dest;\n\n// Create directory if it does not yet exist\nif (!dir.isDirectory()) dir.createDirectory();\n\n// Copy file into directory\nfile.copy(dir);\n\n// Copy file to another file\ndest = dir.open(\"readme2.txt\");\nfile.copy(dest);\n\n// Rename file\nfile.rename(\"readme3.txt\");\n\n// Move file into directory\nfile.move(dir);\n\n// Create hard link\ndest = dir.open(\"readme4.txt\");\nfile.createLink(dest);\n\n// Create symbolic link\ndest = dir.open(\"readme5.txt\");\nfile.createSymbolicLink(dest);\n\n// Delete file\nfile.remove();\n\n// Delete directory (only if empty)\ndir.removeDirectory();\n```\n\n\n### Reading and writing to files\n\nTo read and write files, standard C++ streams are applied. To open an input stream for a\nfile, call *createInputStream*. To create an output stream, call *createOutputStream*.\n\n```C++\nFileHandle file = fs::open(\"readme.txt\");\n\nstd::unique_ptr\u003cstd::istream\u003e in = file.createInputStream();\n// ...\n\nstd::unique_ptr\u003cstd::ostream\u003e out = file.createOutputStream();\n// ...\n```\n\nFor convience, there are also functions for reading and writing entire files using strings:\n\n```C++\nFileHandle file = fs::open(\"readme.txt\");\n\nstd::string content = file.readFile();\n\nfile.writeFile(\"no more text ...\");\n```\n\n\n### Advanced functions on files\n\nAdvanced file operation include the generation of hashes and base64 encoding of files.\nThey can be called directly on a file handle:\n\n```C++\nFileHandle file = fs::open(\"readme.txt\");\n\n// Get SHA1 hash of a file\nstd::string hash = file.sha1();\n\n// Get base64 encoding of a file\nstd::string base64 = file.base64();\n\n// Write file from base64 encoding\nfile.writeFileBase64(base64);\n```\n\n\n### Accessing and traversing directories\n\nA *FileHandle* is used to access files as well as directories.\nTo check if a file handle points to a directory, the function\n*isDirectory* can be used.\n\n```C++\nFileHandle dir = fs::open(\"data\");\nif (dir.isDirectory())\n{\n    // ...\n}\n```\n\nTo list all files in a directory, call *listFiles*:\n\n```C++\nFileHandle dir = fs::open(\"data\");\nstd::vector\u003cstd::string\u003e files = dir.listFiles();\n```\n\nFor better control, the C++ iterator interface can be used:\n\n```C++\nFileHandle dir = fs::open(\"data\");\nfor (FileIterator it = dir.begin(); it != dir.end(); ++it)\n{\n    std::string path = *it;\n}\n```\n\nFor automatically traversing a directory tree, the *traverse*\nfunction can be called. It can be passed  either\n- a callback function for each file entry\n- a callback function for each file and one for each directory\n- a visitor object\n\n```C++\nFileHandle dir = fs::open(\"data\");\n\n// Traverse all file entries\ndir.traverse([](FileHandle \u0026 fh) -\u003e bool {\n    std::cout \u003c\u003c fh.path() \u003c\u003c std::endl;\n    return true; // continue\n});\n\n// Traverse all files and directories\ndir.traverse([](FileHandle \u0026 fh) -\u003e bool {\n    std::cout \u003c\u003c fh.path() \u003c\u003c std::endl;\n    return true; // continue\n}, [](FileHandle \u0026 dir) -\u003e bool {\n    std::cout \u003c\u003c dir.path() \u003c\u003c std::endl;\n    return true; // continue\n});\n```\n\nWhen a handle to a directory has been obtained, it can\nbe used to open file handles relative to that directory:\n\n```C++\nFileHandle dir = fs::open(\"data\");\n\n// Open parent directory\nFileHandle parentDir = dir.parentDirectory();\n\n// Open file in directory\nFileHandle file1 = dir.open(\"readme.txt\");\n\n// Open file relative to directory\nFileHandle file2 = dir.open(\"../readme.txt\");\n```\n\n\n### File trees and diffs\n\nFor higher level operations on directory trees, the classes *Tree*, *Diff*,\nand *Change* can be used. A *Tree* contains the information about all files\nand directories in a tree data structure. It can be obtained from a\ndirectory handle by calling *readTree*.\n\n```C++\n// Read directory tree from current directory\nstd::unique_ptr\u003cTree\u003e tree1 = dir.readTree();\n\n// Read directory tree from current directory, giving it a virtual root\nstd::unique_ptr\u003cTree\u003e tree2 = dir.readTree(\"/root\");\n```\n\nGiven two directory trees, the differences between them can be calculated,\nresulting in a diff object. A diff contains a number of file system operations\nthat need to be performed in order to transform from the source tree to\nthe destination tree. This can be utilized to implement basic file syncing:\n\n```C++\n// Open directories\nFileHandle srcDir = fs::open(\"data1\");\nFileHandle dstDir = fs::open(\"data2\");\n\n// Read both directory trees\nauto srcTree = srcDir.readTree();\nauto dstTree = dstDir.readTree();\n\n// Calculate differences\nauto diff = dstTree-\u003ecreateDiff(*srcTree);\n\n// Sync directories\nfor (Change change : diff-\u003echanges())\n{\n    if (change.operation() == Change::CopyFile) {\n        FileHandle src = srcDir.open(change.path());\n        FileHandle dst = dstDir.open(change.path());\n        src.copy(dst);\n    }\n\n    if (change.operation() == Change::CopyDir) {\n        FileHandle src = srcDir.open(change.path());\n        FileHandle dst = dstDir.open(change.path());\n        src.copyDirectoryRec(dst);\n    }\n\n    if (change.operation() == Change::RemoveFile) {\n        FileHandle dst = dstDir.open(change.path());\n        dst.remove();\n    }\n\n    if (change.operation() == Change::RemoveDir) {\n        FileHandle dst = dstDir.open(change.path());\n        dst.removeDirectoryRec();\n    }\n}\n```\n","funding_links":[],"categories":["HarmonyOS","C++"],"sub_categories":["Windows Manager"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcginternals%2Fcppfs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcginternals%2Fcppfs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcginternals%2Fcppfs/lists"}