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),
374 IEnumerable<string>? ignore,
375 Func<string, string, ValueTask>? postCopyCallback,
376 SemaphoreSlim? semaphore,
377 CancellationToken cancellationToken)
379 var dir =
new DirectoryInfo(src);
380 Task? subdirCreationTask =
null;
381 foreach (var subDirectory
in dir.EnumerateDirectories())
383 if (ignore !=
null && ignore.Contains(subDirectory.Name))
386 var checkingSubdirCreationTask =
true;
387 foreach (var copyTask
in CopyDirectoryImpl(subDirectory.FullName, Path.Combine(dest, subDirectory.Name),
null, postCopyCallback, semaphore, cancellationToken))
389 if (subdirCreationTask ==
null)
391 subdirCreationTask = copyTask;
392 yield
return subdirCreationTask;
394 else if (!checkingSubdirCreationTask)
395 yield
return copyTask;
397 checkingSubdirCreationTask =
false;
401 foreach (var fileInfo
in dir.EnumerateFiles())
403 if (subdirCreationTask ==
null)
406 yield
return subdirCreationTask;
409 if (ignore !=
null && ignore.Contains(fileInfo.Name))
412 var sourceFile = fileInfo.FullName;
413 var destFile =
ConcatPath(dest, fileInfo.Name);
415 async Task CopyThisFile()
417 await subdirCreationTask.WaitAsync(cancellationToken);
418 using var lockContext = semaphore !=
null
421 await
CopyFile(sourceFile, destFile, cancellationToken);
422 if (postCopyCallback !=
null)
423 await postCopyCallback(sourceFile, destFile);
426 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 directo...
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 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 r...
Task< DateTimeOffset > GetLastModified(string path, CancellationToken cancellationToken)
Get the DateTimeOffset of when a given path was last modified. A Task<TResult> resulting in the Date...
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)
Asyncronously locks a semaphore .
Interface for using filesystems.