-
Notifications
You must be signed in to change notification settings - Fork 0
StorageObject Class
Provides an abstract base class for file system storage objects, encapsulating common functionality such as path validation, resource management, and change notification.
Namespace: Rheo.Storage.Core
Assembly: Rheo.Storage.dll
public abstract class StorageObject : IStorageObjectObject → StorageObject
- FileHandler
- DirectoryHandler
| Constructor | Description |
|---|---|
| StorageObject(String, Boolean) | Initializes a new instance of the StorageObject class with the specified file system path, optionally validating and creating the parent directory if necessary. |
| Property | Type | Description |
|---|---|---|
| Information | IStorageInformation | Gets or sets metadata information about the storage object. |
| Name | String | Gets the name of the storage object, typically the file or directory name. |
| ParentDirectory | String | Gets the full path of the parent directory for the current file or directory. |
| FullPath | String | Gets or sets the full path of the file or directory. |
| IsDisposed | Boolean | Gets a value indicating whether this storage object has been disposed. |
| StateLock | Lock | Gets the internal lock object used to synchronize access to the state of this storage object. |
| Event | Description |
|---|---|
| Changed | Occurs when the storage content changes. |
| Method | Description |
|---|---|
| Dispose() | Releases all resources used by the current instance of the class. |
| GetBufferSize() | Calculates the recommended buffer size based on the current storage information. |
| ThrowIfDisposed() | Throws an ObjectDisposedException if this storage object has been disposed. |
| ToString() | Returns a string representation of the storage object. |
| GetValidPath(String) | Validates the specified path and returns its absolute form if it meets the required criteria. |
| WaitForFileAvailableAsync(String, Int32, Int32, CancellationToken) | Asynchronously waits until the specified file becomes available for exclusive read/write access, or until the operation times out. |
| WaitForFileAvailable(String, Int32, Int32) | Waits for a file to become available for access within a specified timeout period. |
| WaitForDirectoryAvailableAsync(String, Int32, Int32, CancellationToken) | Asynchronously waits until the specified directory becomes available for access or until the operation times out. |
| WaitForDirectoryAvailable(String, Int32, Int32) | Waits for the specified directory to become available within a given timeout period. |
The StorageObject class serves as a foundation for implementing file- or directory-based storage abstractions. It manages the association with a file system path, ensures the existence of parent directories, and provides thread-safe state management. Derived classes should implement the required members to provide specific storage behaviors. The class supports change notification through the Changed event and implements resource cleanup via IDisposable. Instances should not be used after they have been disposed.
This class uses the Curiously Recurring Template Pattern (CRTP) to provide common functionality while allowing derived classes to specialize behavior.
Initializes a new instance of the StorageObject class with the specified file system path, optionally validating and creating the parent directory if necessary.
protected StorageObject(string path, bool validated)path String
The file system path to associate with the storage object. This can be either a validated or unvalidated path, depending on the value of the validated parameter.
validated Boolean
true to indicate that the path has already been validated; false to validate the path and ensure the parent directory exists before use.
If validated is false, the constructor validates the provided path and creates the parent directory if it does not already exist. This ensures that the storage object is always associated with a valid and accessible file system location.
Gets or sets metadata information about the storage object, such as size, attributes, and timestamps.
public abstract IStorageInformation Information { get; protected set; }An object containing detailed metadata about the storage item.
This property must be implemented by derived classes. It is automatically updated when changes are detected through the Changed event.
Gets the name of the storage object, typically the file or directory name.
public abstract string Name { get; }The name of the file or directory without the path.
This property must be implemented by derived classes.
Gets the full path of the parent directory for the current file or directory.
public string ParentDirectory { get; }The absolute path to the parent directory.
Gets or sets the full path of the file or directory.
public string FullPath { get; protected set; }The complete absolute path to the storage object.
This property is automatically updated when the storage object is moved or renamed through the Changed event.
Gets a value indicating whether this storage object has been disposed.
public bool IsDisposed { get; }true if the object has been disposed; otherwise, false.
Use this property to check the disposal state before performing operations. Most methods will throw an ObjectDisposedException if called after disposal.
Gets the internal lock object used to synchronize access to the state of this storage object.
public Lock StateLock { get; }A lock object for thread-safe state management.
Use this lock to ensure thread-safe access to the storage object's state in derived classes.
Occurs when the storage content changes.
public event EventHandler<StorageChangedEventArgs>? ChangedEventHandler<StorageChangedEventArgs>
This event is raised whenever the storage object is modified, moved, or deleted. When a deletion is detected, the object automatically disposes itself. Subscribers can use this event to track changes and respond accordingly.
Releases all resources used by the current instance of the class.
public virtual void Dispose()Call this method when you are finished using the object to release any resources it is holding. After calling Dispose, the object should not be used. This method can be overridden in a derived class to release additional resources.
Calculates the recommended buffer size based on the current storage information.
public int GetBufferSize()An integer representing the recommended buffer size in bytes, ranging from 1 KB to 16 MB.
Thrown if storage information is not initialized.
This method provides an optimal buffer size for I/O operations based on the storage object's size. The buffer size is calculated to aim for approximately 100 chunks, with a minimum of 1 KB and a maximum of 16 MB.
Throws an ObjectDisposedException if this storage object has been disposed.
public void ThrowIfDisposed()Thrown if the object has already been disposed.
This method is typically called at the beginning of public methods to ensure the object is in a valid state before performing operations.
Returns a string representation of the storage object.
public override string ToString()A string containing the storage object's information, or a message indicating information is not available.
Validates the specified path and returns its absolute form if it meets the required criteria.
protected virtual string GetValidPath(string path)path String
The file system path to validate. Cannot be null, empty, or consist only of white-space characters, and must not contain invalid path characters.
The absolute path corresponding to the specified path if it passes validation.
Thrown if the path is null, empty, consists only of white-space characters, or contains invalid path characters.
Use this method to ensure that a path is valid and appropriate for the intended file or directory operation before proceeding. The method can be overridden in derived classes to provide additional validation logic.
Asynchronously waits until the specified file becomes available for exclusive read/write access, or until the operation times out.
protected static Task<bool> WaitForFileAvailableAsync(
string filePath,
int timeoutMilliseconds = 10000,
int checkIntervalMilliseconds = 200,
CancellationToken cancellationToken = default
)filePath String
The full path of the file to check for availability. Cannot be null or empty.
timeoutMilliseconds Int32
The maximum time, in milliseconds, to wait for the file to become available. Specify 0 or a negative value to wait indefinitely. The default is 10,000 milliseconds (10 seconds).
checkIntervalMilliseconds Int32
The interval, in milliseconds, between successive checks for file availability. The default is 200 milliseconds.
cancellationToken CancellationToken
A cancellation token that can be used to cancel the wait operation.
A task that represents the asynchronous operation. The task result is true if the file became available within the specified timeout; otherwise, false.
Thrown if filePath is null or empty.
This method repeatedly attempts to open the file with exclusive access to determine its availability. If the file does not exist or remains locked by another process, the method waits and retries until the timeout is reached or the operation is canceled. The method is thread-safe and can be used to coordinate access to files shared between processes.
Waits for a file to become available for access within a specified timeout period.
protected static bool WaitForFileAvailable(
string filePath,
int timeoutMilliseconds = 10000,
int checkIntervalMilliseconds = 200
)filePath String
The full path of the file to check for availability. Cannot be null or empty.
timeoutMilliseconds Int32
The maximum amount of time, in milliseconds, to wait for the file to become available. Must be greater than zero. The default is 10,000 milliseconds.
checkIntervalMilliseconds Int32
The interval, in milliseconds, between availability checks. Must be greater than zero. The default is 200 milliseconds.
true if the file becomes available within the specified timeout period; otherwise, false.
This method blocks the calling thread until the file is available or the timeout elapses. Use this method when synchronous waiting is required. For asynchronous scenarios, use WaitForFileAvailableAsync.
Asynchronously waits until the specified directory becomes available for access or until the operation times out.
protected static Task<bool> WaitForDirectoryAvailableAsync(
string dirPath,
int timeoutMilliseconds = 10000,
int checkIntervalMilliseconds = 200,
CancellationToken cancellationToken = default
)dirPath String
The full path of the directory to check for availability. Cannot be null or empty.
timeoutMilliseconds Int32
The maximum time, in milliseconds, to wait for the directory to become available. Specify 0 for an infinite timeout. The default is 10,000 milliseconds.
checkIntervalMilliseconds Int32
The interval, in milliseconds, between successive checks for directory availability. The default is 200 milliseconds.
cancellationToken CancellationToken
A cancellation token that can be used to cancel the wait operation.
A task that represents the asynchronous operation. The task result is true if the directory became available within the specified timeout; otherwise, false.
Thrown if dirPath is null or empty.
This method checks for both the existence of the directory and the ability to access it. On Windows, it attempts to open a handle to the directory; on other platforms, it tries to enumerate files within the directory. The method periodically checks availability until the directory is accessible, the timeout elapses, or the operation is canceled.
Waits for the specified directory to become available within a given timeout period.
protected static bool WaitForDirectoryAvailable(
string dirPath,
int timeoutMilliseconds = 10000,
int checkIntervalMilliseconds = 200
)dirPath String
The full path of the directory to check for availability. Cannot be null or empty.
timeoutMilliseconds Int32
The maximum amount of time, in milliseconds, to wait for the directory to become available. Must be greater than zero. The default is 10,000 milliseconds.
checkIntervalMilliseconds Int32
The interval, in milliseconds, between availability checks. Must be greater than zero. The default is 200 milliseconds.
true if the directory becomes available within the specified timeout period; otherwise, false.
This method blocks the calling thread until the directory is available or the timeout elapses. Use this method when synchronous waiting is required; for asynchronous scenarios, use WaitForDirectoryAvailableAsync.
The following example demonstrates how to create a custom storage class:
using Rheo.Storage.Core;
using Rheo.Storage.Contracts;
using Rheo.Storage.Information;
public class CustomStorageObject : StorageObject
{
private FileInformation _info;
public CustomStorageObject(string path) : base(path, validated: false)
{
_info = new FileInformation(path);
}
public override IStorageInformation Information
{
get => _info;
protected set => _info = (FileInformation)value;
}
public override string Name => Path.GetFileName(FullPath);
}The following example shows how to use StateLock for thread-safe operations:
using Rheo.Storage;
using var file = new FileObject(@"C:\Documents\file.txt");
// Thread-safe state access
lock (file.StateLock)
{
Console.WriteLine($"Current path: {file.FullPath}");
Console.WriteLine($"Size: {file.Information.Size}");
}The following example demonstrates waiting for a file to become available:
using Rheo.Storage.Core;
public class MyStorageHandler : StorageObject
{
public MyStorageHandler(string path) : base(path, false) { }
public async Task ProcessFileAsync(string filePath)
{
// Wait up to 30 seconds for the file to become available
bool isAvailable = await WaitForFileAvailableAsync(
filePath,
timeoutMilliseconds: 30000,
checkIntervalMilliseconds: 500
);
if (isAvailable)
{
Console.WriteLine("File is now available for processing.");
// Process the file
}
else
{
Console.WriteLine("Timeout: File is still locked.");
}
}
// Required abstract members
public override IStorageInformation Information { get; protected set; }
public override string Name => Path.GetFileName(FullPath);
}The following example shows how to respond to storage changes:
using Rheo.Storage;
using var file = new FileObject(@"C:\Documents\file.txt");
file.Changed += (sender, e) =>
{
Console.WriteLine($"Change detected: {e.ChangeType}");
if (e.NewInfo != null)
{
Console.WriteLine($"New path: {e.NewInfo.AbsolutePath}");
Console.WriteLine($"New size: {e.NewInfo.Size}");
}
};
// Perform operations that trigger changes
file.Move(@"C:\Documents\renamed.txt");The following example demonstrates custom path validation:
using Rheo.Storage.Core;
using Rheo.Storage.Contracts;
public class RestrictedStorageObject : StorageObject
{
private readonly string _allowedDirectory;
public RestrictedStorageObject(string path, string allowedDirectory)
: base(path, validated: false)
{
_allowedDirectory = allowedDirectory;
}
protected override string GetValidPath(string path)
{
// Call base validation first
string validPath = base.GetValidPath(path);
// Add custom validation
if (!validPath.StartsWith(_allowedDirectory, StringComparison.OrdinalIgnoreCase))
{
throw new ArgumentException(
$"Path must be within {_allowedDirectory}",
nameof(path)
);
}
return validPath;
}
// Required abstract members
public override IStorageInformation Information { get; protected set; }
public override string Name => Path.GetFileName(FullPath);
}The StorageObject class provides thread-safe state management through the StateLock property. The Changed event handler and internal state updates are synchronized using this lock. Derived classes should use StateLock when accessing or modifying shared state.
-
Storage Objects
-
Storage Information
-
Platform-Specific
-
Content-Type Analysis
-
Results
-
Models
-
-
Events & Progress