diff --git a/src/ModularPipelines/FileSystem/File.cs b/src/ModularPipelines/FileSystem/File.cs
index ba736a8fbb..e3558fc1d2 100644
--- a/src/ModularPipelines/FileSystem/File.cs
+++ b/src/ModularPipelines/FileSystem/File.cs
@@ -163,6 +163,19 @@ public File Create()
return this;
}
+ ///
+ /// Asynchronously creates a new file at the current path.
+ ///
+ /// This file instance for method chaining.
+ public async Task CreateAsync()
+ {
+ LogFileOperation("Creating File: {Path} [Module: {ModuleName}, Activity: {ActivityId}]", this);
+
+ var fileStream = System.IO.File.Create(Path);
+ await fileStream.DisposeAsync().ConfigureAwait(false);
+ return this;
+ }
+
/// >
public FileAttributes Attributes
{
@@ -192,6 +205,21 @@ public void Delete()
FileInfo.Delete();
}
+ ///
+ /// Asynchronously deletes the file.
+ ///
+ ///
+ /// Uses thread pool offloading as no native async delete API exists in .NET.
+ /// For true async I/O, consider using stream-based operations where available.
+ ///
+ /// Cancellation token.
+ public Task DeleteAsync(CancellationToken cancellationToken = default)
+ {
+ LogFileOperation("Deleting File: {Path} [Module: {ModuleName}, Activity: {ActivityId}]", this);
+
+ return Task.Run(() => FileInfo.Delete(), cancellationToken);
+ }
+
/// >
public File MoveTo(string path)
{
@@ -210,6 +238,43 @@ public File MoveTo(Folder folder)
return MoveTo(System.IO.Path.Combine(folder.Path, Name));
}
+ ///
+ /// Asynchronously moves the file to a new path.
+ ///
+ ///
+ /// Uses thread pool offloading as no native async move API exists in .NET.
+ ///
+ /// The destination path.
+ /// Cancellation token.
+ /// This file instance for method chaining.
+ public Task MoveToAsync(string path, CancellationToken cancellationToken = default)
+ {
+ LogFileOperationWithDestination("Moving File: {Source} > {Destination} [Module: {ModuleName}, Activity: {ActivityId}]", this, path);
+
+ return Task.Run(() =>
+ {
+ FileInfo.MoveTo(path);
+ return this;
+ }, cancellationToken);
+ }
+
+ ///
+ /// Asynchronously moves the file to a folder.
+ ///
+ ///
+ /// Uses thread pool offloading as no native async move API exists in .NET.
+ ///
+ /// The destination folder.
+ /// Cancellation token.
+ /// This file instance for method chaining.
+ public async Task MoveToAsync(Folder folder, CancellationToken cancellationToken = default)
+ {
+ LogFileOperationWithDestination("Moving File: {Source} > {Destination} [Module: {ModuleName}, Activity: {ActivityId}]", this, folder);
+
+ await folder.CreateAsync().ConfigureAwait(false);
+ return await MoveToAsync(System.IO.Path.Combine(folder.Path, Name), cancellationToken).ConfigureAwait(false);
+ }
+
/// >
public File CopyTo(string path)
{
@@ -226,6 +291,37 @@ public File CopyTo(Folder folder)
return CopyTo(System.IO.Path.Combine(folder.Path, Name));
}
+ ///
+ /// Asynchronously copies the file to a new path using stream-based copying.
+ ///
+ /// The destination path.
+ /// Cancellation token.
+ /// A new File instance representing the copied file.
+ public async Task CopyToAsync(string path, CancellationToken cancellationToken = default)
+ {
+ LogFileOperationWithDestination("Copying File: {Source} > {Destination} [Module: {ModuleName}, Activity: {ActivityId}]", this, path);
+
+ await using var sourceStream = System.IO.File.OpenRead(Path);
+ await using var destStream = System.IO.File.Create(path);
+ await sourceStream.CopyToAsync(destStream, cancellationToken).ConfigureAwait(false);
+
+ return new File(path);
+ }
+
+ ///
+ /// Asynchronously copies the file to a folder using stream-based copying.
+ ///
+ /// The destination folder.
+ /// Cancellation token.
+ /// A new File instance representing the copied file.
+ public async Task CopyToAsync(Folder folder, CancellationToken cancellationToken = default)
+ {
+ LogFileOperationWithDestination("Copying File: {Source} > {Destination} [Module: {ModuleName}, Activity: {ActivityId}]", this, folder);
+
+ await folder.CreateAsync().ConfigureAwait(false);
+ return await CopyToAsync(System.IO.Path.Combine(folder.Path, Name), cancellationToken).ConfigureAwait(false);
+ }
+
public static File GetNewTemporaryFilePath()
{
var path = System.IO.Path.Combine(System.IO.Path.GetTempPath(), System.IO.Path.GetRandomFileName());
diff --git a/src/ModularPipelines/FileSystem/Folder.cs b/src/ModularPipelines/FileSystem/Folder.cs
index 185054f276..2ecab8cf5e 100644
--- a/src/ModularPipelines/FileSystem/Folder.cs
+++ b/src/ModularPipelines/FileSystem/Folder.cs
@@ -96,6 +96,25 @@ public Folder Create()
return this;
}
+ ///
+ /// Asynchronously creates the folder if it does not exist.
+ ///
+ ///
+ /// Uses thread pool offloading as no native async directory creation API exists in .NET.
+ ///
+ /// Optional cancellation token.
+ /// This folder instance for method chaining.
+ public Task CreateAsync(CancellationToken cancellationToken = default)
+ {
+ LogFolderOperation("Creating Folder: {Path} [Module: {ModuleName}, Activity: {ActivityId}]", this);
+
+ return Task.Run(() =>
+ {
+ Directory.CreateDirectory(Path);
+ return this;
+ }, cancellationToken);
+ }
+
public void Delete()
{
LogFolderOperation("Deleting Folder: {Path} [Module: {ModuleName}, Activity: {ActivityId}]", this);
@@ -103,6 +122,20 @@ public void Delete()
DirectoryInfo.Delete(true);
}
+ ///
+ /// Asynchronously deletes the folder and all its contents.
+ ///
+ ///
+ /// Uses thread pool offloading as no native async delete API exists in .NET.
+ ///
+ /// Cancellation token.
+ public Task DeleteAsync(CancellationToken cancellationToken = default)
+ {
+ LogFolderOperation("Deleting Folder: {Path} [Module: {ModuleName}, Activity: {ActivityId}]", this);
+
+ return Task.Run(() => DirectoryInfo.Delete(true), cancellationToken);
+ }
+
///
/// Removes all files and subdirectories within the folder.
///
@@ -270,6 +303,91 @@ public Folder CopyTo(string targetPath, bool preserveTimestamps)
return new Folder(targetPath);
}
+ ///
+ /// Asynchronously copies the folder and its contents to the specified target path using stream-based file copying.
+ ///
+ /// The destination path for the copied folder.
+ /// Cancellation token.
+ /// A new instance representing the copied folder.
+ public Task CopyToAsync(string targetPath, CancellationToken cancellationToken = default)
+ {
+ return CopyToAsync(targetPath, preserveTimestamps: false, cancellationToken);
+ }
+
+ ///
+ /// Asynchronously copies the folder and its contents to the specified target path using stream-based file copying.
+ ///
+ /// The destination path for the copied folder.
+ ///
+ /// When true, preserves CreationTimeUtc, LastWriteTimeUtc, and LastAccessTimeUtc
+ /// for all files and directories.
+ ///
+ /// Cancellation token.
+ /// A new instance representing the copied folder.
+ public async Task CopyToAsync(string targetPath, bool preserveTimestamps, CancellationToken cancellationToken = default)
+ {
+ LogFolderOperationWithDestination("Copying Folder: {Source} > {Destination} [Module: {ModuleName}, Activity: {ActivityId}]", this, targetPath);
+
+ Directory.CreateDirectory(targetPath);
+
+ // Copy all subdirectories first
+ foreach (var dirPath in Directory.EnumerateDirectories(this, "*", SearchOption.AllDirectories))
+ {
+ cancellationToken.ThrowIfCancellationRequested();
+
+ var sourceDir = new DirectoryInfo(dirPath);
+ var relativePath = System.IO.Path.GetRelativePath(this, dirPath);
+ var newPath = System.IO.Path.Combine(targetPath, relativePath);
+ var targetDir = Directory.CreateDirectory(newPath);
+
+ targetDir.Attributes = sourceDir.Attributes;
+
+ if (preserveTimestamps)
+ {
+ targetDir.CreationTimeUtc = sourceDir.CreationTimeUtc;
+ targetDir.LastWriteTimeUtc = sourceDir.LastWriteTimeUtc;
+ targetDir.LastAccessTimeUtc = sourceDir.LastAccessTimeUtc;
+ }
+ }
+
+ // Copy all files using async stream copying
+ foreach (var filePath in Directory.EnumerateFiles(this, "*", SearchOption.AllDirectories))
+ {
+ cancellationToken.ThrowIfCancellationRequested();
+
+ var sourceFile = new FileInfo(filePath);
+ var relativePath = System.IO.Path.GetRelativePath(this, filePath);
+ var newPath = System.IO.Path.Combine(targetPath, relativePath);
+
+ await using var sourceStream = System.IO.File.OpenRead(filePath);
+ await using var destStream = System.IO.File.Create(newPath);
+ await sourceStream.CopyToAsync(destStream, cancellationToken).ConfigureAwait(false);
+
+ var targetFile = new FileInfo(newPath);
+ targetFile.Attributes = sourceFile.Attributes;
+
+ if (preserveTimestamps)
+ {
+ targetFile.CreationTimeUtc = sourceFile.CreationTimeUtc;
+ targetFile.LastWriteTimeUtc = sourceFile.LastWriteTimeUtc;
+ targetFile.LastAccessTimeUtc = sourceFile.LastAccessTimeUtc;
+ }
+ }
+
+ // Preserve root directory attributes and timestamps
+ var targetRootDir = new DirectoryInfo(targetPath);
+ targetRootDir.Attributes = DirectoryInfo.Attributes;
+
+ if (preserveTimestamps)
+ {
+ targetRootDir.CreationTimeUtc = DirectoryInfo.CreationTimeUtc;
+ targetRootDir.LastWriteTimeUtc = DirectoryInfo.LastWriteTimeUtc;
+ targetRootDir.LastAccessTimeUtc = DirectoryInfo.LastAccessTimeUtc;
+ }
+
+ return new Folder(targetPath);
+ }
+
public Folder MoveTo(string path)
{
LogFolderOperationWithDestination("Moving Folder: {Source} > {Destination} [Module: {ModuleName}, Activity: {ActivityId}]", this, path);
@@ -278,6 +396,26 @@ public Folder MoveTo(string path)
return this;
}
+ ///
+ /// Asynchronously moves the folder to a new path.
+ ///
+ ///
+ /// Uses thread pool offloading as no native async move API exists in .NET.
+ ///
+ /// The destination path.
+ /// Cancellation token.
+ /// This folder instance for method chaining.
+ public Task MoveToAsync(string path, CancellationToken cancellationToken = default)
+ {
+ LogFolderOperationWithDestination("Moving Folder: {Source} > {Destination} [Module: {ModuleName}, Activity: {ActivityId}]", this, path);
+
+ return Task.Run(() =>
+ {
+ DirectoryInfo.MoveTo(path);
+ return this;
+ }, cancellationToken);
+ }
+
public Folder GetFolder(string name)
{
var directoryInfo = new DirectoryInfo(System.IO.Path.Combine(Path, name));