IO abstraction
Overview
The IFileProvider
interface in .NET Core already provides file system abstraction, but it has a very simple signature and is only intended for reading files. For this reason, Smartstore provides the IFileSystem interface, along with IFile and IDirectory. Their signatures are comprehensive and more aligned with the classes in System.IO
, which you should be more familiar with.
IFileSystem
also implements IFileProvider
and both IFile
and IDirectory
implement IFileInfo
. So think of it as a kind of extension to IFileProvider
. All Smartstore IO interfaces have async methods that IFileProvider
doesn’t provide. This is necessary, because IFileSystem
can also represent cloud storage providers (such as Azure BLOB storage) and virtualize database-driven file storage.
The virtual file system uses the forward slash (/
) as path delimiter and has no concept of volumes or drives. All paths are specified and returned as relative paths to the root of the virtual file system. Absolute paths that use a leading slash (/
), dot (.
) or parent traversal (../
) are not supported.
The default implementation of IFileProvider
is LocalFileSystem. It looks for files using the local disk file system. The async methods delegate to the sync methods.
Here are some basic examples:
// Get the current directory path
var currentDirPath = System.IO.Directory.GetCurrentDirectory();
var localFS = new LocalFileSystem(currentDirPath);
// Get the "MyTemplates" directory
var currentDir = localFS.GetDirectory("MyTemplates");
// Get a list of files in the "MyTemplates" directory
var files = currentDir.EnumerateFiles();
// Get the first file
var firstFile = files.FirstOrDefault();
// Read the first 20 bytes of the file
var inStream = firstFile.OpenRead();
var buffer = new byte[20];
inStream.Read(buffer);
inStream.Dispose();
// Convert buffer to string
string firstString = System.Text.Encoding.Default.GetString(buffer);
var dirListing = "Directory_Listing.txt";
// Check for unique file name
var isNotUnique = localFS.CheckUniqueFileName(dirListing, out var uniqueDirListing);
// Create new file instance
var file = localFS.CreateFile(isNotUnique ? uniqueDirListing : dirListing);
// Create some content
var numberOfFiles = currentDir.CountFiles(deep: false);
var fileNames = new string[files.Count()];
// List all files in current directory
for (var i = 0; i < numberOfFiles; i++)
{
fileNames[i] = files.ElementAt(i).Name;
}
var content = $"The first File in this directory starts with:\n\"{firstString}\"\n\n"
+ $"The {numberOfFiles} files included are:\n\n" + fileNames.StrJoin("\n");
// Write contents to file
var outStream = file.OpenWrite();
outStream.Write(content.ToAsciiBytes());
outStream.Dispose();
Adapters & decorators
ExpandedFileSystem
The ExpandedFileSystem is a decorator that takes a path prefix and an inner IFileSystem
instance. Its root path is expanded with the specified prefix.
var storeRoot = new LocalFileSystem(System.IO.Directory.GetCurrentDirectory());
// Count all the english email templates
var efs = new ExpandedFileSystem("/App_Data/EmailTemplates", storeRoot);
// "en" actually resolves to "/App_Data/EmailTemplates/en"
var numberOfFiles = efs.CountFiles("en");
CompositeFileSystem
The CompositeFileSystem is an adapter that looks up files using a collection of IFileSystem
instances. Because it implements the IFileSystem
interface, it can be used in the same way.
var storeRoot = new LocalFileSystem(System.IO.Directory.GetCurrentDirectory());
var controllerRoot = new LocalFileSystem(
storeRoot.GetDirectory("Controllers").PhysicalPath
);
var viewRoot = new LocalFileSystem(
storeRoot.GetDirectory("Views").PhysicalPath
);
var cfs = new CompositeFileSystem(controllerRoot, viewRoot);
var hasShoppingCartController = cfs.FileExists("ShoppingCartController.cs");
var hasShoppingCartViewDir = cfs.DirectoryExists("ShoppingCart");
Special utilities
DirectoryHasher
The DirectoryHasher creates a hash of the contents of a directory. It can load and persist the hash code for comparison with any previous state, that are saved in App_Data/Tenants/Default/Hash. By default, it scans flat, but you can choose to scan deep as well.
var storeRoot = new LocalFileSystem(System.IO.Directory.GetCurrentDirectory());
var hasher = storeRoot.GetDirectoryHasher("Controllers", deep: true);
var hash = hasher.CurrentHash;
Last updated
Was this helpful?