tools/code/common/FileSystem.cs (85 lines of code) (raw):
using LanguageExt;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text.Json.Nodes;
using System.Threading;
using System.Threading.Tasks;
namespace common;
public static class DirectoryInfoExtensions
{
public static DirectoryInfo GetChildDirectory(this DirectoryInfo directory, string path) =>
new(Path.Combine(directory.FullName, path));
public static FileInfo GetChildFile(this DirectoryInfo directory, string path) =>
new(Path.Combine(directory.FullName, path));
public static Option<DirectoryInfo> TryGetParentDirectory(this DirectoryInfo directory) =>
directory.Parent is DirectoryInfo parent
? parent
: Option<DirectoryInfo>.None;
public static IEnumerable<DirectoryInfo> ListDirectories(this DirectoryInfo directory, string directoryPattern) =>
directory.Exists()
? directory.EnumerateDirectories(directoryPattern)
: [];
/// <summary>
/// Refreshes the state of the directory, then checks if it exists. There are times when simply checking
/// <seealso cref="DirectoryInfo.Exists"/> returns false even though the directory exists.
/// </summary>
/// <param name="directory"></param>
/// <returns></returns>
public static bool Exists(this DirectoryInfo directory)
{
directory.Refresh();
return directory.Exists;
}
public static IEnumerable<FileInfo> ListFiles(this DirectoryInfo directory, string filePattern) =>
directory.Exists()
? directory.EnumerateFiles(filePattern)
: [];
public static void ForceDelete(this DirectoryInfo directory)
{
if (directory.Exists() is false)
{
return;
};
directory.EnumerateFiles("*", SearchOption.AllDirectories)
.Iter(file =>
{
if (file.IsReadOnly)
{
file.IsReadOnly = false;
}
});
directory.Delete(recursive: true);
}
}
public static class FileInfoExtensions
{
public static async ValueTask OverwriteWithBinaryData(this FileInfo file, BinaryData data, CancellationToken cancellationToken)
{
file.EnsureDirectoryExists();
await File.WriteAllBytesAsync(file.FullName, data.ToArray(), cancellationToken);
}
public static async ValueTask OverwriteWithJson(this FileInfo file, JsonNode json, CancellationToken cancellationToken)
{
var binaryData = BinaryData.FromObjectAsJson(json, JsonObjectExtensions.SerializerOptions);
await file.OverwriteWithBinaryData(binaryData, cancellationToken);
}
private static void EnsureDirectoryExists(this FileInfo file)
{
var directory = file.Directory
?? throw new InvalidOperationException($"File {file.FullName} has a null directory.");
if (!directory.Exists)
{
directory.Create();
}
}
public static async ValueTask<T> ReadAsJson<T>(this FileInfo file, CancellationToken cancellationToken)
{
var binaryData = await file.ReadAsBinaryData(cancellationToken);
return binaryData.ToObjectFromJson<T>();
}
public static async ValueTask<BinaryData> ReadAsBinaryData(this FileInfo file, CancellationToken cancellationToken)
{
using var stream = file.OpenRead();
return await BinaryData.FromStreamAsync(stream, cancellationToken);
}
/// <summary>
/// Refreshes the state of the file, then checks if it exists. There are times when simply checking
/// <seealso cref="FileInfo.Exists"/> returns false even though the file exists.
/// </summary>
/// <param name="file"></param>
/// <returns></returns>
public static bool Exists(this FileInfo file)
{
file.Refresh();
return file.Exists;
}
}