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 foreach (var subDir
in dir.EnumerateDirectories())
52 foreach (var file
in dir.EnumerateFiles())
54 cancellationToken.ThrowIfCancellationRequested();
57 file.Attributes = FileAttributes.Normal;
60 catch (FileNotFoundException)
66 cancellationToken.ThrowIfCancellationRequested();
72 IEnumerable<string>? ignore,
73 Func<string, string, ValueTask>? postCopyCallback,
77 CancellationToken cancellationToken)
79 ArgumentNullException.ThrowIfNull(src);
80 ArgumentNullException.ThrowIfNull(src);
82 if (taskThrottle.HasValue && taskThrottle < 1)
83 throw new ArgumentOutOfRangeException(nameof(taskThrottle), taskThrottle,
"taskThrottle must be at least 1!");
88 using var semaphore = taskThrottle.HasValue ?
new SemaphoreSlim(taskThrottle.Value) :
null;
89 await Task.WhenAll(
CopyDirectoryImpl(src, dest, ignore, postCopyCallback, semaphore, cancellationToken));
93 public string ConcatPath(params
string[] paths) => Path.Combine(paths);
96 public async ValueTask
CopyFile(
string src,
string dest, CancellationToken cancellationToken)
98 ArgumentNullException.ThrowIfNull(src);
99 ArgumentNullException.ThrowIfNull(dest);
102 await
using var srcStream =
new FileStream(
106 FileShare.Read | FileShare.Delete,
108 FileOptions.Asynchronous | FileOptions.SequentialScan);
112 await srcStream.CopyToAsync(destStream, 81920, cancellationToken);
122 var di =
new DirectoryInfo(path);
124 return Task.CompletedTask;
126 return Task.Factory.StartNew(
130 TaskScheduler.Current);
143 public string GetDirectoryName(
string path) => Path.GetDirectoryName(path ??
throw new ArgumentNullException(nameof(path)))
144 ??
throw new InvalidOperationException($
"Null was returned. Path ({path}) must be rooted. This is not supported!");
147 public string GetFileName(
string path) => Path.GetFileName(path ??
throw new ArgumentNullException(nameof(path)));
150 public string GetFileNameWithoutExtension(
string path) => Path.GetFileNameWithoutExtension(path ??
throw new ArgumentNullException(nameof(path)));
153 public Task<List<string>>
GetFilesWithExtension(
string path,
string extension,
bool recursive, CancellationToken cancellationToken) => Task.Factory.StartNew(
157 ArgumentNullException.ThrowIfNull(extension);
158 var results =
new List<string>();
159 foreach (var fileName
in Directory.EnumerateFiles(
162 recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly))
164 cancellationToken.ThrowIfCancellationRequested();
165 results.Add(fileName);
172 TaskScheduler.Current);
175 public Task
MoveFile(
string source,
string destination, CancellationToken cancellationToken) => Task.Factory.StartNew(
178 ArgumentNullException.ThrowIfNull(destination);
179 source =
ResolvePath(source ??
throw new ArgumentNullException(nameof(source)));
181 File.Move(source, destination);
185 TaskScheduler.Current);
188 public Task
MoveDirectory(
string source,
string destination, CancellationToken cancellationToken) => Task.Factory.StartNew(
191 ArgumentNullException.ThrowIfNull(destination);
192 source =
ResolvePath(source ??
throw new ArgumentNullException(nameof(source)));
194 Directory.Move(source, destination);
198 TaskScheduler.Current);
201 public async ValueTask<byte[]>
ReadAllBytes(
string path, CancellationToken cancellationToken)
204 await
using var file =
new FileStream(
208 FileShare.ReadWrite | FileShare.Delete,
210 FileOptions.Asynchronous | FileOptions.SequentialScan);
212 buf =
new byte[file.Length];
213 await file.ReadAsync(buf, cancellationToken);
221 public virtual string ResolvePath(
string path) => Path.GetFullPath(path ??
throw new ArgumentNullException(nameof(path)));
224 public async ValueTask
WriteAllBytes(
string path,
byte[] contents, CancellationToken cancellationToken)
227 await file.WriteAsync(contents, cancellationToken);
234 return new FileStream(
238 FileShare.Read | FileShare.Delete,
240 FileOptions.Asynchronous | FileOptions.SequentialScan);
244 public Task<IReadOnlyList<string>>
GetDirectories(
string path, CancellationToken cancellationToken) => Task.Factory.StartNew(
248 var results =
new List<string>();
249 cancellationToken.ThrowIfCancellationRequested();
250 foreach (var directoryName
in Directory.EnumerateDirectories(path))
252 results.Add(directoryName);
253 cancellationToken.ThrowIfCancellationRequested();
256 return (IReadOnlyList<string>)results;
260 TaskScheduler.Current);
263 public Task<IReadOnlyList<string>>
GetFiles(
string path, CancellationToken cancellationToken) => Task.Factory.StartNew(
267 var results =
new List<string>();
268 cancellationToken.ThrowIfCancellationRequested();
269 foreach (var fileName
in Directory.EnumerateFiles(path))
271 results.Add(fileName);
272 cancellationToken.ThrowIfCancellationRequested();
275 return (IReadOnlyList<string>)results;
279 TaskScheduler.Current);
282 public Task
ZipToDirectory(
string path,
Stream zipFile, CancellationToken cancellationToken) => Task.Factory.StartNew(
286 ArgumentNullException.ThrowIfNull(zipFile);
289#error Check if zip file seeking has been addressesed. See https:
293 if (!zipFile.CanSeek)
294 throw new ArgumentException(
"Stream does not support seeking!", nameof(zipFile));
296 using var archive =
new ZipArchive(zipFile, ZipArchiveMode.Read,
true);
297 archive.ExtractToDirectory(path);
301 TaskScheduler.Current);
307 Path.DirectorySeparatorChar,
308 Path.AltDirectorySeparatorChar,
311 ??
throw new ArgumentNullException(nameof(path));
314 public Task<DateTimeOffset>
GetLastModified(
string path, CancellationToken cancellationToken) => Task.Factory.StartNew(
317 path =
ResolvePath(path ??
throw new ArgumentNullException(nameof(path)));
318 var fileInfo =
new FileInfo(path);
319 return new DateTimeOffset(fileInfo.LastWriteTimeUtc);
323 TaskScheduler.Current);
330 FileShare.Read | FileShare.Delete | (shareWrite ? FileShare.Write : FileShare.None),
347 IEnumerable<string>? ignore,
348 Func<string, string, ValueTask>? postCopyCallback,
349 SemaphoreSlim? semaphore,
350 CancellationToken cancellationToken)
352 var dir =
new DirectoryInfo(src);
353 Task? subdirCreationTask =
null;
354 foreach (var subDirectory
in dir.EnumerateDirectories())
356 if (ignore !=
null && ignore.Contains(subDirectory.Name))
359 var checkingSubdirCreationTask =
true;
360 foreach (var copyTask
in CopyDirectoryImpl(subDirectory.FullName, Path.Combine(dest, subDirectory.Name),
null, postCopyCallback, semaphore, cancellationToken))
362 if (subdirCreationTask ==
null)
364 subdirCreationTask = copyTask;
365 yield
return subdirCreationTask;
367 else if (!checkingSubdirCreationTask)
368 yield
return copyTask;
370 checkingSubdirCreationTask =
false;
374 foreach (var fileInfo
in dir.EnumerateFiles())
376 if (subdirCreationTask ==
null)
379 yield
return subdirCreationTask;
382 if (ignore !=
null && ignore.Contains(fileInfo.Name))
385 var sourceFile = fileInfo.FullName;
386 var destFile =
ConcatPath(dest, fileInfo.Name);
388 async Task CopyThisFile()
390 await subdirCreationTask.WaitAsync(cancellationToken);
391 using var lockContext = semaphore !=
null
394 await
CopyFile(sourceFile, destFile, cancellationToken);
395 if (postCopyCallback !=
null)
396 await postCopyCallback(sourceFile, destFile);
399 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.
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.