wabbajack/Wabbajack.Paths.IO/AbsolutePathExtensions.cs

336 lines
11 KiB
C#
Raw Permalink Normal View History

2021-09-27 12:42:46 +00:00
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.AccessControl;
2021-09-27 12:42:46 +00:00
using System.Text;
using System.Threading;
using System.Threading.Tasks;
2021-10-23 16:51:17 +00:00
namespace Wabbajack.Paths.IO;
public static class AbsolutePathExtensions
2021-09-27 12:42:46 +00:00
{
2021-10-23 16:51:17 +00:00
public const int BufferSize = 1024 * 128;
public static Stream Open(this AbsolutePath file, FileMode mode, FileAccess access = FileAccess.Read,
FileShare share = FileShare.ReadWrite)
2021-09-27 12:42:46 +00:00
{
2021-10-23 16:51:17 +00:00
return File.Open(file.ToNativePath(), mode, access, share);
}
2021-09-27 12:42:46 +00:00
2021-10-23 16:51:17 +00:00
public static void Delete(this AbsolutePath file)
{
var path = file.ToNativePath();
if (File.Exists(path))
{
try
{
File.Delete(path);
}
2022-10-07 21:02:16 +00:00
catch (UnauthorizedAccessException)
{
var fi = new FileInfo(path);
if (fi.IsReadOnly)
{
fi.IsReadOnly = false;
File.Delete(path);
}
else
{
throw;
}
}
catch (IOException ex)
{
if (ex.Message.Contains("because it is being used by another process"))
{
Thread.Sleep(1000);
File.Delete(path);
}
else
{
throw;
}
}
}
2021-10-23 16:51:17 +00:00
if (Directory.Exists(path))
file.DeleteDirectory();
2021-10-23 16:51:17 +00:00
}
2021-09-27 12:42:46 +00:00
2021-10-23 16:51:17 +00:00
public static long Size(this AbsolutePath file)
{
return new FileInfo(file.ToNativePath()).Length;
}
2021-09-27 12:42:46 +00:00
2021-10-23 16:51:17 +00:00
public static DateTime LastModifiedUtc(this AbsolutePath file)
{
return new FileInfo(file.ToNativePath()).LastWriteTimeUtc;
}
2022-10-30 13:16:12 +00:00
public static DateTime CreatedUtc(this AbsolutePath file)
{
return new FileInfo(file.ToNativePath()).CreationTimeUtc;
}
2021-09-27 12:42:46 +00:00
2021-10-23 16:51:17 +00:00
public static DateTime LastModified(this AbsolutePath file)
{
return new FileInfo(file.ToNativePath()).LastWriteTime;
}
public static void Touch(this AbsolutePath file)
{
new FileInfo(file.ToNativePath()).LastWriteTime = DateTime.Now;
}
2021-09-27 12:42:46 +00:00
2021-10-23 16:51:17 +00:00
public static byte[] ReadAllBytes(this AbsolutePath file)
{
using var s = File.Open(file.ToNativePath(), FileMode.Open, FileAccess.Read, FileShare.Read);
var remain = s.Length;
var length = remain;
var bytes = new byte[length];
2021-09-27 12:42:46 +00:00
2021-10-23 16:51:17 +00:00
while (remain > 0) remain -= s.Read(bytes, (int) Math.Min(length - remain, 1024 * 1024), bytes.Length);
2021-09-27 12:42:46 +00:00
2021-10-23 16:51:17 +00:00
return bytes;
}
2021-09-27 12:42:46 +00:00
2021-10-23 16:51:17 +00:00
public static string ReadAllText(this AbsolutePath file)
{
return Encoding.UTF8.GetString(file.ReadAllBytes());
}
2021-09-27 12:42:46 +00:00
2021-10-23 16:51:17 +00:00
public static async IAsyncEnumerable<string> ReadAllLinesAsync(this AbsolutePath file)
{
await using var fs = file.Open(FileMode.Open);
var sr = new StreamReader(fs);
while (true)
2021-09-27 12:42:46 +00:00
{
2021-10-23 16:51:17 +00:00
var line = await sr.ReadLineAsync();
if (line == null) break;
yield return line;
2021-09-27 12:42:46 +00:00
}
2021-10-23 16:51:17 +00:00
}
2021-09-27 12:42:46 +00:00
2021-10-23 16:51:17 +00:00
public static IEnumerable<string> ReadAllLines(this AbsolutePath file)
{
using var fs = file.Open(FileMode.Open);
var sr = new StreamReader(fs);
while (true)
2021-09-27 12:42:46 +00:00
{
2021-10-23 16:51:17 +00:00
var line = sr.ReadLine();
if (line == null) break;
yield return line;
2021-09-27 12:42:46 +00:00
}
2021-10-23 16:51:17 +00:00
}
2021-09-27 12:42:46 +00:00
2021-10-23 16:51:17 +00:00
public static async Task<string> ReadAllTextAsync(this AbsolutePath file)
{
return Encoding.UTF8.GetString(await file.ReadAllBytesAsync());
}
2021-09-27 12:42:46 +00:00
2021-10-23 16:51:17 +00:00
public static async ValueTask<byte[]> ReadAllBytesAsync(this AbsolutePath file,
CancellationToken token = default)
{
await using var s = File.Open(file.ToNativePath(), FileMode.Open, FileAccess.Read, FileShare.Read);
var remain = s.Length;
var length = remain;
var bytes = new byte[length];
2021-09-27 12:42:46 +00:00
2021-10-23 16:51:17 +00:00
while (remain > 0)
remain -= await s.ReadAsync(bytes.AsMemory((int) Math.Min(length - remain, 1024 * 1024), bytes.Length),
token);
2021-09-27 12:42:46 +00:00
2021-10-23 16:51:17 +00:00
return bytes;
}
2021-09-27 12:42:46 +00:00
2021-10-23 16:51:17 +00:00
public static void WriteAllBytes(this AbsolutePath file, ReadOnlySpan<byte> data)
{
using var s = file.Open(FileMode.Create, FileAccess.Write, FileShare.None);
s.Write(data);
}
public static async Task WriteAllAsync(this AbsolutePath file, Stream srcStream, CancellationToken token,
bool closeWhenDone = true)
{
var buff = new byte[BufferSize];
await using var dest = file.Open(FileMode.Create, FileAccess.Write, FileShare.None);
while (true)
2021-09-27 12:42:46 +00:00
{
2021-10-23 16:51:17 +00:00
var read = await srcStream.ReadAsync(buff.AsMemory(0, BufferSize), token);
if (read == 0)
break;
await dest.WriteAsync(buff.AsMemory(0, read), token);
2021-09-27 12:42:46 +00:00
}
2021-10-23 16:51:17 +00:00
if (closeWhenDone)
await srcStream.DisposeAsync();
}
2021-09-27 12:42:46 +00:00
2021-10-23 16:51:17 +00:00
public static async Task WriteAllLinesAsync(this AbsolutePath file, IEnumerable<string> src,
CancellationToken token, bool closeWhenDone = true)
{
await using var dest = file.Open(FileMode.Create, FileAccess.Write, FileShare.None);
await using var sw = new StreamWriter(dest, Encoding.UTF8);
2021-09-27 12:42:46 +00:00
2021-10-23 16:51:17 +00:00
foreach (var line in src) await sw.WriteLineAsync(line);
2021-09-27 12:42:46 +00:00
2021-10-23 16:51:17 +00:00
await sw.DisposeAsync();
}
public static async Task WriteAllLinesAsync(this AbsolutePath file, IEnumerable<string> src,
FileMode fileMode, CancellationToken token)
{
await using var dest = file.Open(fileMode, FileAccess.Write, FileShare.None);
await using var sw = new StreamWriter(dest, Encoding.UTF8);
foreach (var line in src) await sw.WriteLineAsync(line);
await sw.DisposeAsync();
}
2021-09-27 12:42:46 +00:00
2021-10-23 16:51:17 +00:00
public static async ValueTask WriteAllBytesAsync(this AbsolutePath file, Memory<byte> data,
CancellationToken token = default)
{
await using var s = file.Open(FileMode.Create, FileAccess.Write, FileShare.None);
await s.WriteAsync(data, token);
}
2021-09-27 12:42:46 +00:00
2021-10-23 16:51:17 +00:00
public static async ValueTask MoveToAsync(this AbsolutePath src, AbsolutePath dest, bool overwrite,
CancellationToken token)
{
// TODO: Make this async
2022-06-29 13:18:04 +00:00
var srcStr = src.ToString();
var destStr = dest.ToString();
var fi = new FileInfo(srcStr);
if (fi.IsReadOnly)
fi.IsReadOnly = false;
var fid = new FileInfo(destStr);
if (dest.FileExists() && fid.IsReadOnly)
{
fid.IsReadOnly = false;
}
2022-10-04 04:43:21 +00:00
var retries = 0;
while (true)
2022-06-29 13:18:04 +00:00
{
2022-10-04 04:43:21 +00:00
try
{
File.Move(srcStr, destStr, overwrite);
return;
}
2022-10-07 21:02:16 +00:00
catch (Exception)
2022-10-04 04:43:21 +00:00
{
if (retries > 10)
throw;
retries++;
await Task.Delay(TimeSpan.FromSeconds(1), token);
}
2022-06-29 13:18:04 +00:00
}
2021-10-23 16:51:17 +00:00
}
2021-09-27 12:42:46 +00:00
2022-10-07 21:02:16 +00:00
public static async ValueTask CopyToAsync(this AbsolutePath src, AbsolutePath dest,
2021-10-23 16:51:17 +00:00
CancellationToken token)
{
2022-10-07 21:02:16 +00:00
await using var inf = src.Open(FileMode.Open, FileAccess.Read, FileShare.Read);
await using var ouf = dest.Open(FileMode.Create, FileAccess.Write, FileShare.Read);
await inf.CopyToAsync(ouf, token);
2021-10-23 16:51:17 +00:00
}
2021-09-27 12:42:46 +00:00
2021-10-23 16:51:17 +00:00
public static void WriteAllText(this AbsolutePath file, string str)
{
file.WriteAllBytes(Encoding.UTF8.GetBytes(str));
}
2021-09-27 12:42:46 +00:00
2021-10-23 16:51:17 +00:00
public static async Task WriteAllTextAsync(this AbsolutePath file, string str,
CancellationToken token = default)
{
await file.WriteAllBytesAsync(Encoding.UTF8.GetBytes(str), token);
}
2021-09-27 12:42:46 +00:00
2021-10-23 16:51:17 +00:00
private static string ToNativePath(this AbsolutePath file)
{
return file.ToString();
}
2021-09-27 12:42:46 +00:00
public static async Task CopyToAsync(this Stream from, AbsolutePath path, CancellationToken token = default)
{
await using var to = path.Open(FileMode.Create, FileAccess.Write, FileShare.None);
await from.CopyToAsync(to, token);
}
public static async Task CopyToAsync(this AbsolutePath from, Stream to, CancellationToken token = default)
{
await using var fromStream = from.Open(FileMode.Open, FileAccess.Read, FileShare.Read);
await fromStream.CopyToAsync(to, token);
}
2021-10-23 16:51:17 +00:00
#region Directories
2021-09-27 12:42:46 +00:00
2021-10-23 16:51:17 +00:00
public static void CreateDirectory(this AbsolutePath path)
{
2021-10-23 23:18:43 +00:00
if (path.Depth > 1 && !path.Parent.DirectoryExists())
path.Parent.CreateDirectory();
2021-10-23 16:51:17 +00:00
Directory.CreateDirectory(ToNativePath(path));
}
2021-09-27 12:42:46 +00:00
2021-10-23 16:51:17 +00:00
public static void DeleteDirectory(this AbsolutePath path, bool dontDeleteIfNotEmpty = false)
{
if (!path.DirectoryExists()) return;
if (dontDeleteIfNotEmpty && (path.EnumerateFiles().Any() || path.EnumerateDirectories().Any())) return;
2021-12-19 21:52:06 +00:00
foreach (var directory in Directory.GetDirectories(path.ToString()))
2021-12-19 21:52:06 +00:00
{
DeleteDirectory(directory.ToAbsolutePath(), dontDeleteIfNotEmpty);
}
try
{
var di = new DirectoryInfo(path.ToString());
if (di.Attributes.HasFlag(FileAttributes.ReadOnly))
di.Attributes &= ~FileAttributes.ReadOnly;
2022-06-29 13:18:04 +00:00
Directory.Delete(path.ToString(), true);
2021-12-19 21:52:06 +00:00
}
catch (UnauthorizedAccessException)
{
Directory.Delete(path.ToString(), true);
}
2021-10-23 16:51:17 +00:00
}
2021-09-27 12:42:46 +00:00
2021-10-23 16:51:17 +00:00
public static bool DirectoryExists(this AbsolutePath path)
{
return path != default && Directory.Exists(path.ToNativePath());
}
2021-09-27 12:42:46 +00:00
2021-10-23 16:51:17 +00:00
public static bool FileExists(this AbsolutePath path)
{
if (path == default) return false;
return File.Exists(path.ToNativePath());
}
2021-09-27 12:42:46 +00:00
2021-10-23 16:51:17 +00:00
public static IEnumerable<AbsolutePath> EnumerateFiles(this AbsolutePath path, string pattern = "*",
bool recursive = true)
{
return Directory.EnumerateFiles(path.ToString(), pattern,
recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly)
.Select(file => file.ToAbsolutePath());
}
2021-09-27 12:42:46 +00:00
2021-10-23 16:51:17 +00:00
public static IEnumerable<AbsolutePath> EnumerateFiles(this AbsolutePath path, Extension pattern,
bool recursive = true)
{
return Directory.EnumerateFiles(path.ToString(), "*" + pattern,
recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly)
.Select(file => file.ToAbsolutePath());
}
2021-09-27 12:42:46 +00:00
2021-10-23 16:51:17 +00:00
public static IEnumerable<AbsolutePath> EnumerateDirectories(this AbsolutePath path, bool recursive = true)
{
2022-07-11 20:55:54 +00:00
if (!path.DirectoryExists()) return Array.Empty<AbsolutePath>();
2021-10-23 16:51:17 +00:00
return Directory.EnumerateDirectories(path.ToString(), "*",
recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly)
.Select(p => (AbsolutePath) p);
2021-09-27 12:42:46 +00:00
}
2021-10-23 16:51:17 +00:00
#endregion
2021-09-27 12:42:46 +00:00
}