|
@@ -0,0 +1,132 @@
|
|
|
+using System.IO.Enumeration;
|
|
|
+using FNZCM2.Abstractions.Models.Fs;
|
|
|
+
|
|
|
+namespace FNZCM2.Abstractions.Utility;
|
|
|
+
|
|
|
+using FSE = (bool isDir, string path, long size, System.DateTimeOffset lastWrited);
|
|
|
+
|
|
|
+public static class FolderScan
|
|
|
+{
|
|
|
+ public static FolderScanResult Scan(string folderPath)
|
|
|
+ {
|
|
|
+ List<IFsEntry> allEntries = new();
|
|
|
+ List<FolderEntry> allFolders = new();
|
|
|
+ List<FileEntry> allFiles = new();
|
|
|
+
|
|
|
+ Dictionary<string, long> folderPathToIdCache = new();
|
|
|
+ long GetFolderId(string path)
|
|
|
+ {
|
|
|
+ if (folderPathToIdCache.TryGetValue(path, out var fid)) return fid;
|
|
|
+
|
|
|
+ var parts = path.Split(Path.DirectorySeparatorChar);
|
|
|
+
|
|
|
+ fid = 0;
|
|
|
+ foreach (var s in parts)
|
|
|
+ {
|
|
|
+ var d = allFolders.First(p => p.FolderId == fid && p.Name == s);
|
|
|
+ fid = d.Id;
|
|
|
+ }
|
|
|
+
|
|
|
+ folderPathToIdCache[path] = fid;
|
|
|
+ return fid;
|
|
|
+ }
|
|
|
+
|
|
|
+ var fullPath = Path.GetFullPath(folderPath);
|
|
|
+
|
|
|
+ var fse = new FileSystemEnumerable<FSE>(
|
|
|
+ fullPath,
|
|
|
+ (ref FileSystemEntry p) => new(
|
|
|
+ p.IsDirectory,
|
|
|
+ p.ToFullPath(),
|
|
|
+ p.Length,
|
|
|
+ p.LastWriteTimeUtc
|
|
|
+ ),
|
|
|
+ new()
|
|
|
+ {
|
|
|
+ RecurseSubdirectories = true,
|
|
|
+ });
|
|
|
+
|
|
|
+ var trimPathPrefixLength = fullPath.Length + 1;
|
|
|
+
|
|
|
+ foreach (var e in fse)
|
|
|
+ {
|
|
|
+ var rPath = e.path.Substring(trimPathPrefixLength);
|
|
|
+
|
|
|
+ var directoryName = Path.GetDirectoryName(rPath);
|
|
|
+ var fileName = Path.GetFileName(rPath);
|
|
|
+ var folderId = string.IsNullOrEmpty(directoryName) ? 0 : GetFolderId(directoryName!);
|
|
|
+
|
|
|
+ if (e.isDir)
|
|
|
+ {
|
|
|
+ var folderEntry = new FolderEntry
|
|
|
+ {
|
|
|
+ Id = DateTime.Now.Ticks,
|
|
|
+ FolderId = folderId,
|
|
|
+ Name = fileName,
|
|
|
+ LastChangedTime = e.lastWrited,
|
|
|
+ };
|
|
|
+
|
|
|
+ allEntries.Add(folderEntry);
|
|
|
+ allFolders.Add(folderEntry);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ var fileEntry = new FileEntry
|
|
|
+ {
|
|
|
+ Id = DateTime.Now.Ticks,
|
|
|
+ FolderId = folderId,
|
|
|
+ Name = fileName,
|
|
|
+ LastChangedTime = e.lastWrited,
|
|
|
+ Size = e.size,
|
|
|
+ };
|
|
|
+
|
|
|
+ allEntries.Add(fileEntry);
|
|
|
+ allFiles.Add(fileEntry);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ var allById = allEntries.ToDictionary(e => e.Id);
|
|
|
+ var allInFolder = allEntries
|
|
|
+ .GroupBy(e => e.FolderId)
|
|
|
+ .ToDictionary(g => g.Key, g => (IReadOnlyList<IFsEntry>)g.ToArray());
|
|
|
+
|
|
|
+ var folderById = allFolders.ToDictionary(f => f.Id);
|
|
|
+ var foldersInFolder = allFolders
|
|
|
+ .GroupBy(f => f.FolderId)
|
|
|
+ .ToDictionary(g => g.Key, g => (IReadOnlyList<FolderEntry>)g.ToArray());
|
|
|
+
|
|
|
+ var fileById = allFiles.ToDictionary(f => f.Id);
|
|
|
+ var filesInFolder = allFiles
|
|
|
+ .GroupBy(f => f.FolderId)
|
|
|
+ .ToDictionary(g => g.Key, g => (IReadOnlyList<FileEntry>)g.ToArray());
|
|
|
+
|
|
|
+ return new FolderScanResult
|
|
|
+ {
|
|
|
+ All = allEntries,
|
|
|
+ AllById = allById,
|
|
|
+ AllInFolder = allInFolder,
|
|
|
+ Folders = allFolders,
|
|
|
+ FolderById = folderById,
|
|
|
+ FoldersInFolder = foldersInFolder,
|
|
|
+ Files = allFiles,
|
|
|
+ FileById = fileById,
|
|
|
+ FilesInFolder = filesInFolder,
|
|
|
+ //add folderPathToIdCache on demands
|
|
|
+ };
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+public class FolderScanResult
|
|
|
+{
|
|
|
+ public required IReadOnlyList<IFsEntry> All { get; init; }
|
|
|
+ public required IReadOnlyDictionary<long, IFsEntry> AllById { get; init; }
|
|
|
+ public required IReadOnlyDictionary<long, IReadOnlyList<IFsEntry>> AllInFolder { get; init; }
|
|
|
+
|
|
|
+ public required IReadOnlyList<FolderEntry> Folders { get; init; }
|
|
|
+ public required IReadOnlyDictionary<long, FolderEntry> FolderById { get; init; }
|
|
|
+ public required IReadOnlyDictionary<long, IReadOnlyList<FolderEntry>> FoldersInFolder { get; init; }
|
|
|
+
|
|
|
+ public required IReadOnlyList<FileEntry> Files { get; init; }
|
|
|
+ public required IReadOnlyDictionary<long, FileEntry> FileById { get; init; }
|
|
|
+ public required IReadOnlyDictionary<long, IReadOnlyList<FileEntry>> FilesInFolder { get; init; }
|
|
|
+}
|