using System; using System.IO; using System.Threading; using System.Threading.Tasks; using PCL.Core.Logging; using fNbt; namespace PCL.Core.Minecraft; /// /// 提供 NBT 文件的异步读写操作。 /// public static class NbtFileHandler { /// /// 异步读取 NBT 文件中指定 Tag 内容。 /// /// 要读取的 NbtTag 类型,必须继承自 NbtTag。 /// 目标文件路径(完整或相对)。 /// 要读取的 NbtTag 的标签名称。 /// 取消操作的令牌。 /// 一个指定类型的 NbtTag 对象,如果文件或标签不存在则返回 null。 public static async Task ReadTagInNbtFileAsync(string filePath, string tagName, CancellationToken cancelToken = default) where T: NbtTag { try { var fullPath = Path.GetFullPath(filePath); if (!File.Exists(fullPath)) { LogWrapper.Warn($"NBT 文件不存在:{fullPath}"); return null; } const int bufferSize = 4096; var nbtFile = new NbtFile(); await Task.Run(async () => { await using var fs = new FileStream(fullPath, FileMode.Open, FileAccess.Read, FileShare.Read, bufferSize, FileOptions.Asynchronous); nbtFile.LoadFromStream(fs, NbtCompression.AutoDetect); }, cancelToken); var result = nbtFile.RootTag.Get(tagName); if (result is null) { LogWrapper.Warn($"未找到指定的 NBT 标签:{tagName}"); } return result; } catch (OperationCanceledException) { LogWrapper.Info($"读取 NBT 文件操作被取消:{filePath}"); return null; } catch (Exception ex) { LogWrapper.Warn(ex, $"读取 NBT 文件出错:{filePath}"); return null; } } /// /// 异步将指定标签写入 NBT 文件的 RootTag 中。(文件可以不存在) /// /// 要写入文件的 NbtTag 对象。 /// 目标文件路径(完整或相对)。 /// NBT 文件的压缩类型,默认为 NbtCompression.None。 /// 取消操作的令牌。 /// 返回操作是否成功。 public static async Task WriteTagInNbtFileAsync(NbtTag nbtTag, string filePath, NbtCompression compression = NbtCompression.None, CancellationToken cancelToken = default) { try { var fullPath = Path.GetFullPath(filePath); var directoryName = Path.GetDirectoryName(fullPath); if (string.IsNullOrEmpty(directoryName)) { LogWrapper.Warn($"无法获取目标目录:{fullPath}"); return false; } Directory.CreateDirectory(directoryName); var rootTag = new NbtCompound { Name = "" }; rootTag.Add(nbtTag); var nbtFile = new NbtFile(rootTag); const int bufferSize = 4096; await Task.Run(async () => { await using var fs = new FileStream(fullPath, FileMode.Create, FileAccess.Write, FileShare.Read, bufferSize, FileOptions.Asynchronous); nbtFile.SaveToStream(fs, compression); }, cancelToken); LogWrapper.Info($"NBT 文件成功保存于:{fullPath}"); return true; } catch (OperationCanceledException) { LogWrapper.Info($"写入 NBT 文件操作被取消:{filePath}"); return false; } catch (NbtFormatException ex) { LogWrapper.Warn(ex, $"NBT 格式错误:{filePath}"); return false; } catch (IOException ex) { LogWrapper.Warn(ex, $"文件操作错误:{filePath}"); return false; } catch (Exception ex) { LogWrapper.Warn(ex, $"写入 NBT 文件出错:{filePath}"); return false; } } }