Filesystem Interface
The Core::File
API can be used for common filesystem tasks.
Below are some examples of using the File API, refer to Source/core/Filesystem.h
and Source/core/Filesystem.cpp
for all available APIs.
File Handling
Check if file exists
if (Core::File("/tmp/test.txt").Exists()) {
printf("File exists\n");
} else {
printf("File does not exist\n");
}
Create new file
Core::File fileObject("/tmp/test.txt");
fileObject.Create(static_cast<uint32_t>(0755));
// Either close the file manually, or it will be closed automatically in destructor
fileObject.Close();
Delete File
Core::File fileObject("/tmp/test.txt");
file.Destroy();
Move File
Core::File fileObject("/tmp/test.txt");
fileObject.Move("/tmp/newfile.txt");
// The fileObject information is refreshed once moved, so calls to
// methods such as `Name()` will contain the updated values from after the move.
printf("New file path is: %s\n", fileObject.Name().c_str());
Get File Extension
Will return file extension without the leading dot
// Option 1
string extension = Core::File::Extension("/tmp/test.txt");
// Option 2
Core::File fileObject("/tmp/test.txt");
string extension = fileObject.Extension();
Read file contents into memory
Warning
Consider memory usage when reading large files straight into memory. For large files, consider reading and parsing line-by-line to extract only the necessary data if possible
Core::File fileObject("/tmp/test.txt");
// Open() defaults to read-only
if (fileObject.Open()) {
// Successfully opened the file, now read into a buffer
char buffer[1024] = {};
uint32_t read;
string fileContents;
while ((read = fileObject.Read(reinterpret_cast<uint8_t*>(buffer), sizeof(buffer))) != 0) {
fileContents.append(buffer, read);
}
fileObject.Close();
}
Create a new file and write data
Core::File fileObject("/tmp/test.txt");
// Delete file if it already exists
if (fileObject.Exists()) {
fileObject.Destroy();
}
fileObject.Create();
string toWrite = "Some text to write to a file\n";
fileObject.Write(reinterpret_cast<uint8_t*>(toWrite.data()), toWrite.size());
fileObject.Close();
Append to existing file
Core::File fileObject("/tmp/test.txt");
// Open() defaults to opening read-only, pass false to open as r/w
fileObject.Open(false);
fileObject.Position(false, fileObject.Size());
string toWrite = "Text to append to a file\n";
fileObject.Write(reinterpret_cast<uint8_t*>(toWrite.data()), toWrite.size());
fileObject.Close();
Read file line-by-line
This is a more efficient way of parsing large files instead of reading them entirely into memory if only certain information in the file is required
// File will be closed on destruction
Core::DataElementFile fileObject("/tmp/test.txt", Core::File::USER_READ);
Core::TextReader reader(fileObject);
while (!reader.EndOfText()) {
Core::TextFragment line(reader.ReadLine());
if (!line.IsEmpty()) {
printf("Read line: %s\n", line.Text().c_str());
}
}
Directory Handling
Create Directory
Will create directories recursively
Core::Directory("/tmp/subdirectory").CreatePath();
Delete contents of a directory
This will remove everything inside the directory recursively, but will not delete the directory itself
Core::Directory("/tmp/subdirectory").Destroy();
Delete directory
This will delete the contents of the directory and the directory itself
Core::Directory("/tmp/subdirectory").Destroy();
Core::File("/tmp/subdirectory").Destroy();
Iterate over a directory
All Files
Core::Directory dir("/tmp");
while (dir.Next()) {
Core::File currentEntry(dir.Current());
if (!currentEntry.IsDirectory()) {
printf("Found file: %s\n", currentEntry.Name().c_str());
}
}
Globbing
Using an glob wildcard pattern, only iterate over .txt files
Core::Directory dir("/tmp", "*.txt");
while (dir.Next()) {
Core::File currentEntry(dir.Current());
if (!currentEntry.IsDirectory()) {
printf("Found text file: %s\n", currentEntry.Name().c_str());
}
}
Path Handling
Normalisation
For security, use the Normalise()
function when accepting user input to prevent path traversal vulnerabilities. Will attempt to return a safe version of the path if possible. If the path attempts to traverse outside of the current directory then the valid
argument will be set to false.
std::string vulnerablePath = "../../../../passwd";
bool validPath;
Core::File::Normalize(vulnerablePath, validPath);
printf("Safe path: %s\n", validPath ? "true" : "false");
/* Output:
Safe path: false
*/