2
0
mirror of synced 2025-02-09 15:14:15 +00:00

152 lines
4.6 KiB
C#
Raw Normal View History

2023-04-12 16:06:04 +02:00
using Logging;
using Utils;
2023-04-12 16:06:04 +02:00
namespace FileUtils
2023-04-12 16:06:04 +02:00
{
public interface IFileManager
{
2023-09-13 10:03:11 +02:00
TrackedFile CreateEmptyFile(string label = "");
TrackedFile GenerateFile(ByteSize size, string label = "");
2024-07-01 15:59:08 +02:00
TrackedFile GenerateFile(Action<IGenerateOption> options, string label = "");
2023-09-13 10:03:11 +02:00
void DeleteAllFiles();
void ScopedFiles(Action action);
T ScopedFiles<T>(Func<T> action);
2023-04-12 16:06:04 +02:00
}
2024-07-01 15:59:08 +02:00
public interface IGenerateOption
{
IGenerateOption Random(ByteSize size);
IGenerateOption StringRepeat(string str, ByteSize size);
IGenerateOption StringRepeat(string str, int times);
IGenerateOption ByteRepeat(byte[] bytes, ByteSize size);
IGenerateOption ByteRepeat(byte[] bytes, int times);
}
2023-04-12 16:06:04 +02:00
public class FileManager : IFileManager
{
2024-07-01 15:59:08 +02:00
private static readonly NumberSource folderNumberSource = new NumberSource(0);
2023-09-12 10:31:55 +02:00
private readonly ILog log;
2023-04-12 16:06:04 +02:00
private readonly string folder;
2023-09-12 13:32:06 +02:00
private readonly List<List<TrackedFile>> fileSetStack = new List<List<TrackedFile>>();
2023-04-12 16:06:04 +02:00
2024-07-01 15:59:08 +02:00
public const int ChunkSize = 1024 * 1024 * 100;
2023-09-12 10:31:55 +02:00
public FileManager(ILog log, string rootFolder)
2023-04-12 16:06:04 +02:00
{
folder = Path.Combine(rootFolder, folderNumberSource.GetNextNumber().ToString("D5"));
2023-04-12 16:06:04 +02:00
this.log = log;
}
2023-09-13 10:03:11 +02:00
public TrackedFile CreateEmptyFile(string label = "")
2023-04-12 16:06:04 +02:00
{
2023-09-21 10:33:09 +02:00
var path = Path.Combine(folder, Guid.NewGuid().ToString() + ".bin");
EnsureDirectory();
2023-09-12 13:32:06 +02:00
var result = new TrackedFile(log, path, label);
2023-04-12 16:06:04 +02:00
File.Create(result.Filename).Close();
if (fileSetStack.Any()) fileSetStack.Last().Add(result);
2023-04-12 16:06:04 +02:00
return result;
}
2024-07-01 15:59:08 +02:00
public TrackedFile GenerateFile(ByteSize size, string label = "")
{
return GenerateFile(o => o.Random(size), label);
}
public TrackedFile GenerateFile(Action<IGenerateOption> options, string label = "")
2023-04-12 16:06:04 +02:00
{
2023-06-07 09:59:00 +02:00
var sw = Stopwatch.Begin(log);
2024-07-01 15:59:08 +02:00
var result = RunGenerators(options, label);
2024-03-22 13:36:33 +01:00
sw.End($"Generated file {result.Describe()}.");
2023-04-12 16:06:04 +02:00
return result;
}
2023-09-13 10:03:11 +02:00
public void DeleteAllFiles()
2023-04-12 16:06:04 +02:00
{
DeleteDirectory();
2023-04-12 16:06:04 +02:00
}
public void ScopedFiles(Action action)
{
PushFileSet();
action();
PopFileSet();
}
public T ScopedFiles<T>(Func<T> action)
{
PushFileSet();
var result = action();
PopFileSet();
return result;
}
private void PushFileSet()
{
2023-09-12 13:32:06 +02:00
fileSetStack.Add(new List<TrackedFile>());
}
private void PopFileSet()
{
if (!fileSetStack.Any()) return;
var pop = fileSetStack.Last();
fileSetStack.Remove(pop);
foreach (var file in pop)
{
2023-09-21 10:33:09 +02:00
File.Delete(file.Filename);
}
2023-09-21 10:33:09 +02:00
// If the folder is now empty, delete it too.
if (!Directory.GetFiles(folder).Any()) DeleteDirectory();
}
2024-07-01 15:59:08 +02:00
private TrackedFile RunGenerators(Action<IGenerateOption> options, string label)
2023-06-07 09:59:00 +02:00
{
2023-09-13 10:03:11 +02:00
var result = CreateEmptyFile(label);
2024-07-01 15:59:08 +02:00
var generators = GetGenerators(options);
CheckSpaceAvailable(result, generators.GetRequiredSpace());
2023-06-07 09:59:00 +02:00
2024-07-01 15:59:08 +02:00
using var stream = new FileStream(result.Filename, FileMode.Append);
generators.Run(stream);
2023-06-07 09:59:00 +02:00
return result;
}
2024-07-01 15:59:08 +02:00
private GeneratorCollection GetGenerators(Action<IGenerateOption> options)
{
var result = new GeneratorCollection();
options(result);
return result;
}
private void CheckSpaceAvailable(TrackedFile testFile, long requiredSize)
2023-06-07 09:59:00 +02:00
{
var file = new FileInfo(testFile.Filename);
var drive = new DriveInfo(file.Directory!.Root.FullName);
var spaceAvailable = drive.TotalFreeSpace;
2024-07-01 15:59:08 +02:00
if (spaceAvailable < requiredSize)
2023-06-07 09:59:00 +02:00
{
2023-09-20 10:51:47 +02:00
var msg = $"Not enough disk space. " +
2024-07-01 15:59:08 +02:00
$"{Formatter.FormatByteSize(requiredSize)} required. " +
2023-06-07 09:59:00 +02:00
$"{Formatter.FormatByteSize(spaceAvailable)} available.";
log.Log(msg);
2023-09-20 10:51:47 +02:00
throw new Exception(msg);
2023-06-07 09:59:00 +02:00
}
}
private void EnsureDirectory()
{
2023-09-21 10:33:09 +02:00
Directory.CreateDirectory(folder);
}
private void DeleteDirectory()
{
2023-09-21 10:33:09 +02:00
if (Directory.Exists(folder)) Directory.Delete(folder, true);
}
2023-04-12 16:06:04 +02:00
}
}