2021-09-27 12:42:46 +00:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.IO;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
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))
|
|
|
|
|
File.Delete(path);
|
|
|
|
|
if (Directory.Exists(path))
|
|
|
|
|
Directory.Delete(path, true);
|
|
|
|
|
}
|
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;
|
|
|
|
|
}
|
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;
|
|
|
|
|
}
|
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();
|
|
|
|
|
}
|
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
|
|
|
|
|
File.Move(src.ToString(), dest.ToString(), overwrite);
|
|
|
|
|
}
|
2021-09-27 12:42:46 +00:00
|
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
|
public static async ValueTask CopyToAsync(this AbsolutePath src, AbsolutePath dest, bool overwrite,
|
|
|
|
|
CancellationToken token)
|
|
|
|
|
{
|
|
|
|
|
// TODO: Make this async
|
|
|
|
|
File.Copy(src.ToString(), dest.ToString(), overwrite);
|
|
|
|
|
}
|
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
|
|
|
|
|
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)
|
|
|
|
|
{
|
|
|
|
|
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;
|
|
|
|
|
Directory.Delete(ToNativePath(path), true);
|
|
|
|
|
}
|
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)
|
|
|
|
|
{
|
|
|
|
|
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
|
|
|
|
}
|