【问题标题】:Value already read, or no value when trying to read from a Stream值已读取,或尝试从 Stream 读取时没有值
【发布时间】:2021-05-12 19:04:42
【问题描述】:

我已经尝试了很长时间,但它一直给我一个错误。我有一个应该代表 nbt 文档的字节数组。我想将其转换为带有库的 c# 对象:fNbt。

这是我的代码:

byte[] buffer = Convert.FromBase64String(value);
byte[] decompressed;

using (var inputStream = new MemoryStream(buffer))
{
    using var outputStream = new MemoryStream();

    using (var gzip = new GZipStream(inputStream, CompressionMode.Decompress, leaveOpen: true))
    {
        gzip.CopyTo(outputStream);
    }

    fNbt.NbtReader reader = new fNbt.NbtReader(outputStream, true);
    var output = reader.ReadValueAs<AuctionItem>(); //Error: Value already read, or no value to read.
    return output;
}

当我尝试这个时,它可以工作:

            decompressed = outputStream.ToArray();
            outputStream.Seek(0, SeekOrigin.Begin);
            outputStream.Read(new byte[1000], 0, decompressed.Count() - 1);

但是当我尝试这个时,它没有:

            outputStream.Seek(0, SeekOrigin.Begin);
            fNbt.NbtReader reader = new fNbt.NbtReader(outputStream, true);
            reader.ReadValueAs<AuctionItem>();

【问题讨论】:

  • 这个问题够不够好?抱歉,我是 stackoverflow 的新手。
  • “它似乎不起作用” 不是问题描述,这是任何人在这里发帖的唯一原因,所以这只是噪音。如果这是评论中的异常消息,它不是很明显。这确实应该是标题,以便其他遇到此问题的人可以找到它。
  • 此站点是一个 wiki,您的问题是一篇关于您遇到的问题的文章。当问题是例外时,这应该是帖子的焦点。编写代码的原因可能对您很重要,但对于遇到相同问题的未来读者(他们可能出于完全不同的原因处理相同的问题)而言并不重要。
  • 反正我的水晶球说outputStream需要重置到开头。您刚刚写信给它,当前位置现在位于末尾。 NbtReader 如果在最后,就没有什么可读的了。
  • 我该如何解决这个问题!?!?!?另外我会重新制作标题,我才意识到我是智障

标签: c# decode minecraft


【解决方案1】:

NbtReader 与大多数流阅读器一样,从您提供的任何流的当前 位置开始读取。由于您刚刚写完outputStream,那么该位置就是流的结尾。这意味着此时没有什么可阅读的。

解决方案是寻找 outputStream 回到开头,然后再读取它:

outputStream.Seek(0, SeekOrigin.Begin); // <-- seek to the beginning    

// Do the read
fNbt.NbtReader reader = new fNbt.NbtReader(outputStream, true);
var output = reader.ReadValueAs<AuctionItem>(); // No error anymore
return output;

【讨论】:

  • 旁注:我倾向于使用outputStream.Position = 0; 作为倒带流的更简单方法。
  • @JonSkeet 我已经习惯了使用Seek 进行搜索,以至于我什至不再考虑使用Position
  • @Etienne de Martal 我认为您解决了部分问题,但还有更多。如果您想提供更多帮助,请观看我的编辑。
  • 看了源码,问题是NbtReader只把某些数据类型当成“值”。这些将是标量和标量数组,但不是化合物或列表。 ReadValueAs 并非旨在将复合标签转换为任意模型类。它不像 JSON.NET 那样复杂。使用此答案(而不是您添加到问题中的其他内容),致电ReadAsTag 并转换为NbtCompound。您需要单独转换为 AuctionItem 模型类。
  • 非常感谢。我正要放弃这个项目,因为我一直在寻找这么久。现在我意识到,放弃不是一种选择:D。
【解决方案2】:

解决方法如下。 NbtReader.ReadValueAs 不将 nbtCompound 或 nbtList 视为值。我做了这个小阅读器,但还没有完成(完成后我会更新代码)。

    public static T ReadValueAs<T>(string value) where T: new()
    {
        byte[] buffer = Convert.FromBase64String(value);

        using (var inputStream = new MemoryStream(buffer))
        {
            using var outputStream = new MemoryStream();

            using (var gzip = new GZipStream(inputStream, CompressionMode.Decompress, leaveOpen: true))
            {
                gzip.CopyTo(outputStream);
            }
            outputStream.Seek(0, SeekOrigin.Begin);

            return new EasyNbt.NbtReader(outputStream).ReadValueAs<T>();
        }
    }

这是 NbtReader:

    private MemoryStream MemStream { get; set; }

    public NbtReader(MemoryStream memStream)
    {
        MemStream = memStream;
    }

    public T ReadValueAs<T>() where T: new()
    {
        return ReadTagAs<T>(new fNbt.NbtReader(MemStream, true).ReadAsTag());
    }

    private T ReadTagAs<T>(fNbt.NbtTag nbtTag)
    {
        //Reads to the root and adds to T...
    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-05
    • 1970-01-01
    • 2012-10-12
    • 1970-01-01
    • 2018-07-15
    • 2021-04-08
    相关资源
    最近更新 更多