2using System.Collections.Generic;
4using System.IO.Compression;
7using System.Threading.Tasks;
40 cancellationToken.ThrowIfCancellationRequested();
43 if (!dir.Attributes.HasFlag(FileAttributes.Directory) || dir.Attributes.HasFlag(FileAttributes.ReparsePoint))
49 List<Exception>? exceptions =
null;
50 foreach (var subDir
in dir.EnumerateDirectories())
55 catch (AggregateException ex)
57 exceptions ??=
new List<Exception>();
58 exceptions.AddRange(ex.InnerExceptions);
61 foreach (var file
in dir.EnumerateFiles())
63 cancellationToken.ThrowIfCancellationRequested();
66 file.Attributes = FileAttributes.Normal;
71 exceptions ??=
new List<Exception>();
76 cancellationToken.ThrowIfCancellationRequested();
83 exceptions ??=
new List<Exception>();
87 if (exceptions !=
null)
88 throw new AggregateException(exceptions);
93 IEnumerable<string>? ignore,
94 Func<string, string, ValueTask>? postCopyCallback,
98 CancellationToken cancellationToken)
100 ArgumentNullException.ThrowIfNull(src);
101 ArgumentNullException.ThrowIfNull(src);
103 if (taskThrottle.HasValue && taskThrottle < 1)
104 throw new ArgumentOutOfRangeException(nameof(taskThrottle), taskThrottle,
"taskThrottle must be at least 1!");
109 using var semaphore = taskThrottle.HasValue ?
new SemaphoreSlim(taskThrottle.Value) :
null;
110 await Task.WhenAll(
CopyDirectoryImpl(src, dest, ignore, postCopyCallback, semaphore, cancellationToken));
114 public string ConcatPath(params
string[] paths) => Path.Combine(paths);
117 public async ValueTask
CopyFile(
string src,
string dest, CancellationToken cancellationToken)
119 ArgumentNullException.ThrowIfNull(src);
120 ArgumentNullException.ThrowIfNull(dest);
123 await
using var srcStream =
new FileStream(
127 FileShare.Read | FileShare.Delete,
129 FileOptions.Asynchronous | FileOptions.SequentialScan);
133 await srcStream.CopyToAsync(destStream, 81920, cancellationToken);
143 var di =
new DirectoryInfo(path);
145 return Task.CompletedTask;
147 return Task.Factory.StartNew(
151 TaskScheduler.Current);
164 public string GetDirectoryName(
string path) => Path.GetDirectoryName(path ??
throw new ArgumentNullException(nameof(path)))
165 ??
throw new InvalidOperationException($
"Null was returned. Path ({path}) must be rooted. This is not supported!");
168 public string GetFileName(
string path) => Path.GetFileName(path ??
throw new ArgumentNullException(nameof(path)));
171 public string GetFileNameWithoutExtension(
string path) => Path.GetFileNameWithoutExtension(path ??
throw new ArgumentNullException(nameof(path)));
174 public Task<List<string>>
GetFilesWithExtension(
string path,
string extension,
bool recursive, CancellationToken cancellationToken) => Task.Factory.StartNew(
178 ArgumentNullException.ThrowIfNull(extension);
179 var results =
new List<string>();
180 foreach (var fileName
in Directory.EnumerateFiles(
183 recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly))
185 cancellationToken.ThrowIfCancellationRequested();
186 results.Add(fileName);
193 TaskScheduler.Current);
196 public Task
MoveFile(
string source,
string destination, CancellationToken cancellationToken) => Task.Factory.StartNew(
199 ArgumentNullException.ThrowIfNull(destination);
200 source =
ResolvePath(source ??
throw new ArgumentNullException(nameof(source)));
202 File.Move(source, destination);
206 TaskScheduler.Current);
209 public Task
MoveDirectory(
string source,
string destination, CancellationToken cancellationToken) => Task.Factory.StartNew(
212 ArgumentNullException.ThrowIfNull(destination);
213 source =
ResolvePath(source ??
throw new ArgumentNullException(nameof(source)));
215 Directory.Move(source, destination);
219 TaskScheduler.Current);
222 public async ValueTask<byte[]>
ReadAllBytes(
string path, CancellationToken cancellationToken)
226 buf =
new byte[file.Length];
227 await file.ReadAsync(buf, cancellationToken);
235 public virtual string ResolvePath(
string path) => Path.GetFullPath(path ??
throw new ArgumentNullException(nameof(path)));
238 public async ValueTask
WriteAllBytes(
string path,
byte[] contents, CancellationToken cancellationToken)
241 await file.WriteAsync(contents, cancellationToken);
248 return new FileStream(
252 FileShare.Read | FileShare.Delete,
254 FileOptions.Asynchronous | FileOptions.SequentialScan);
261 return new FileStream(
265 FileShare.ReadWrite | FileShare.Delete,
267 FileOptions.Asynchronous | FileOptions.SequentialScan);
271 public Task<IReadOnlyList<string>>
GetDirectories(
string path, CancellationToken cancellationToken) => Task.Factory.StartNew(
275 var results =
new List<string>();
276 cancellationToken.ThrowIfCancellationRequested();
277 foreach (var directoryName
in Directory.EnumerateDirectories(path))
279 results.Add(directoryName);
280 cancellationToken.ThrowIfCancellationRequested();
283 return (IReadOnlyList<string>)results;
287 TaskScheduler.Current);
290 public Task<IReadOnlyList<string>>
GetFiles(
string path, CancellationToken cancellationToken) => Task.Factory.StartNew(
294 var results =
new List<string>();
295 cancellationToken.ThrowIfCancellationRequested();
296 foreach (var fileName
in Directory.EnumerateFiles(path))
298 results.Add(fileName);
299 cancellationToken.ThrowIfCancellationRequested();
302 return (IReadOnlyList<string>)results;
306 TaskScheduler.Current);
309 public Task
ZipToDirectory(
string path,
Stream zipFile, CancellationToken cancellationToken) => Task.Factory.StartNew(
313 ArgumentNullException.ThrowIfNull(zipFile);
316#error Check if zip file seeking has been addressesed. See https:
320 if (!zipFile.CanSeek)
321 throw new ArgumentException(
"Stream does not support seeking!", nameof(zipFile));
323 using var archive =
new ZipArchive(zipFile, ZipArchiveMode.Read,
true);
324 archive.ExtractToDirectory(path);
328 TaskScheduler.Current);
334 Path.DirectorySeparatorChar,
335 Path.AltDirectorySeparatorChar,
338 ??
throw new ArgumentNullException(nameof(path));
341 public Task<DateTimeOffset>
GetLastModified(
string path, CancellationToken cancellationToken) => Task.Factory.StartNew(
344 path =
ResolvePath(path ??
throw new ArgumentNullException(nameof(path)));
345 var fileInfo =
new FileInfo(path);
346 return new DateTimeOffset(fileInfo.LastWriteTimeUtc);
350 TaskScheduler.Current);
357 FileShare.Read | FileShare.Delete | (shareWrite ? FileShare.Write : FileShare.None),
362 public Task<bool>
PathIsChildOf(
string parentPath,
string childPath, CancellationToken cancellationToken) => Task.Factory.StartNew(
368 if (parentPath == childPath)
372 var di1 =
new DirectoryInfo(parentPath);
373 var di2 =
new DirectoryInfo(childPath);
374 while (di2.Parent !=
null)
376 if (di2.Parent.FullName == di1.FullName)
386 TaskScheduler.Current);
401 IEnumerable<string>? ignore,
402 Func<string, string, ValueTask>? postCopyCallback,
403 SemaphoreSlim? semaphore,
404 CancellationToken cancellationToken)
406 var dir =
new DirectoryInfo(src);
407 Task? subdirCreationTask =
null;
408 foreach (var subDirectory
in dir.EnumerateDirectories())
410 if (ignore !=
null && ignore.Contains(subDirectory.Name))
413 var checkingSubdirCreationTask =
true;
414 foreach (var copyTask
in CopyDirectoryImpl(subDirectory.FullName, Path.Combine(dest, subDirectory.Name),
null, postCopyCallback, semaphore, cancellationToken))
416 if (subdirCreationTask ==
null)
418 subdirCreationTask = copyTask;
419 yield
return subdirCreationTask;
421 else if (!checkingSubdirCreationTask)
422 yield
return copyTask;
424 checkingSubdirCreationTask =
false;
428 foreach (var fileInfo
in dir.EnumerateFiles())
430 if (subdirCreationTask ==
null)
433 yield
return subdirCreationTask;
436 if (ignore !=
null && ignore.Contains(fileInfo.Name))
439 var sourceFile = fileInfo.FullName;
440 var destFile =
ConcatPath(dest, fileInfo.Name);
442 async Task CopyThisFile()
444 await subdirCreationTask.WaitAsync(cancellationToken);
445 using var lockContext = semaphore !=
null
448 await
CopyFile(sourceFile, destFile, cancellationToken);
449 if (postCopyCallback !=
null)
450 await postCopyCallback(sourceFile, destFile);
453 yield
return CopyThisFile();
IIOManager that resolves paths to Environment.CurrentDirectory.
IEnumerable< Task > CopyDirectoryImpl(string src, string dest, IEnumerable< string >? ignore, Func< string, string, ValueTask >? postCopyCallback, SemaphoreSlim? semaphore, CancellationToken cancellationToken)
Copies a directory from src to dest .
async ValueTask< byte[]> ReadAllBytes(string path, CancellationToken cancellationToken)
Returns all the contents of a file at path as a byte array.A ValueTask that results in the contents ...
Task DeleteDirectory(string path, CancellationToken cancellationToken)
Recursively delete a directory, removes and does not enter any symlinks encounterd....
virtual string ResolvePath(string path)
Retrieve the full path of some path given a relative path. Must be used before passing relative path...
Task MoveFile(string source, string destination, CancellationToken cancellationToken)
Moves a file at source to destination .A Task representing the running operation.
string ResolvePath()
Retrieve the full path of the current working directory.The full path of the current working director...
Task CreateDirectory(string path, CancellationToken cancellationToken)
Create a directory at path .A Task representing the running operation.
FileStream CreateAsyncSequentialWriteStream(string path)
Creates an asynchronous FileStream for sequential writing.The open FileStream.
Task< IReadOnlyList< string > > GetDirectories(string path, CancellationToken cancellationToken)
Returns full directory names in a given path .A Task<TResult> resulting in the directories in path .
Task< List< string > > GetFilesWithExtension(string path, string extension, bool recursive, CancellationToken cancellationToken)
Gets a list of files in path with the given extension .A Task resulting in a list of paths to files ...
async ValueTask CopyFile(string src, string dest, CancellationToken cancellationToken)
Copy a file from src to dest .A ValueTask representing the running operation.
Task< IReadOnlyList< string > > GetFiles(string path, CancellationToken cancellationToken)
Returns full file names in a given path .A Task<TResult> resulting in the files in path .
Task< bool > FileExists(string path, CancellationToken cancellationToken)
Check that the file at path exists.A Task<TResult> resulting in true if the file at path exists,...
Task MoveDirectory(string source, string destination, CancellationToken cancellationToken)
Moves a directory at source to destination .A Task representing the running operation.
string GetFileNameWithoutExtension(string path)
Gets the file name portion of a path with.The file name portion of path .
Task ZipToDirectory(string path, Stream zipFile, CancellationToken cancellationToken)
Extract a set of zipFile to a given path .A Task representing the running operation.
async ValueTask WriteAllBytes(string path, byte[] contents, CancellationToken cancellationToken)
Writes some contents to a file at path overwriting previous content.A ValueTask representing the ru...
Task< bool > PathIsChildOf(string parentPath, string childPath, CancellationToken cancellationToken)
Check if a given parentPath is a parent of a given parentPath .A Task<TResult> resulting in true if ...
Task< DateTimeOffset > GetLastModified(string path, CancellationToken cancellationToken)
Get the DateTimeOffset of when a given path was last modified.A Task<TResult> resulting in the DateT...
FileStream GetFileStream(string path, bool shareWrite)
Gets the Stream for a given file path .The FileStream of the file.This function is sychronous.
async ValueTask CopyDirectory(IEnumerable< string >? ignore, Func< string, string, ValueTask >? postCopyCallback, string src, string dest, int? taskThrottle, CancellationToken cancellationToken)
Copies a directory from src to dest .A ValueTask representing the running operation.
const int DefaultBufferSize
Default FileStream buffer size used by .NET.
FileStream CreateAsyncSequentialReadStream(string path)
Creates an asynchronous FileStream for sequential reading.The open FileStream.
const string CurrentDirectory
Path to the current working directory for the IIOManager.
string GetDirectoryName(string path)
Gets the directory portion of a given path .The directory portion of the given path .
bool PathContainsParentAccess(string path)
Check if a path contains the '..' parent directory accessor.true if path contains a '....
string ConcatPath(params string[] paths)
Combines an array of strings into a path.The combined path.
const TaskCreationOptions BlockingTaskCreationOptions
The TaskCreationOptions used to spawn Tasks for potentially long running, blocking operations.
static void NormalizeAndDelete(DirectoryInfo dir, CancellationToken cancellationToken)
Recursively empty a directory.
Task DeleteFile(string path, CancellationToken cancellationToken)
Deletes a file at path .A Task representing the running operation.
string GetFileName(string path)
Gets the file name portion of a path .The file name portion of path .
Task< bool > DirectoryExists(string path, CancellationToken cancellationToken)
Check that the directory at path exists.A Task resulting in true if the directory at path exists,...
Async lock context helper.
static async ValueTask< SemaphoreSlimContext > Lock(SemaphoreSlim semaphore, CancellationToken cancellationToken, ILogger? logger=null)
Asyncronously locks a semaphore .
Interface for using filesystems.