如何使用 C# 访问 Avro.snz 文件中的数据

How do I access the data in a Avro.snz file with C#

我有一个 Avro.snz 文件 avro.codecs 活泼 这可以在 Spark 中使用 com.databricks.avro 打开,但 Apache.Avro 和 Confluent.Avro 似乎不支持 snappy,它们只有 deflate 和 null。虽然他们可以给我 Schema,但我无法获取数据。

下一个方法获取和错误。 Ironsnappy 也无法解压缩文件,它说输入是

using (Avro.File.IFileReader<generic> reader = Avro.File.DataFileReader<generic>.OpenReader(avro_path))
{
    schema = reader.GetSchema();
    Console.WriteLine(reader.HasNext()); //true
    var hi = reader.Next(); // error
    Console.WriteLine(hi.ElementAt(0).ToString()); // error
}

我开始想知道 Azure HDInsight 库中是否有任何内容,但我似乎无法找到 nuget 包,它让我能够阅读支持 Snappy 压缩的 Avro。

我愿意接受任何解决方案,即使这意味着下载 Apache.Avro 的源代码并手动添加 Snappy 支持,但老实说,我是个新手,不知道如何做压缩甚至可以工作,更不用说添加对库的支持了。

有人能帮忙吗?

更新: 只是将 snappy 编解码器添加到 Apache.Avro 并将 DeflateStream 更改为 Ironsnappy 流失败。它再次给出了损坏的输入。有什么地方可以用 C# 打开 Snappy 压缩的 Avro 文件吗?

或者我如何确定 Avro 的哪一部分被快速压缩并将其传递给 Ironsnappy。

好的,所以对此甚至没有任何评论。但我最终解决了我的问题。这是我解决它的方法。

  1. 我也尝试了 Apache.Avro 和 Confluent 版本,但是他们的 .net 版本没有快速支持该死的。但是我可以得到架构,因为它显然是未压缩的。
  2. 由于 Parquet.Net 使用 IronSnappy,我 built/added 通过基本上克隆其 deflate 代码并更改一些名称来 Apache.Avro 中的 snappy 编解码器。失败的。 Ironsnappy 说输入错误。
  3. 我研究了 Avro,发现它由未压缩的模式分隔,后跟数据的压缩编解码器的名称,然后是数据本身,它们被分成块。好吧,我不知道块在哪里开始和结束。不知何故,文件中的二进制文件以某种方式提供了该信息,但我仍然不知道,我什至无法使用十六进制编辑器获得它。我认为 Apache.Avro 以某种方式需要 long 或 varint,而我使用的十六进制编辑器没有给我该信息。
  4. 我在 Apache.Avro 中找到了 avro-tools.jar 工具。为了使其更易于使用,我将其制作为带有 launch4j 的可执行文件,这完全是多余的,但无论如何。然后我将我的 avro 猫用到 1 行中,未压缩且活泼。我以此为基础,并在调试器中遵循 Apache.Avro 的流程。同时还使用十六进制编辑器和 C# 中的调试器跟踪字节索引等。
  5. 有1行,就是gua运行teed 1块。所以我 运行 在字节开始索引和结束索引上循环。我找到了我的 Snappy 块,并且能够使用 IronSnappy 将其解压缩。我修改了 Apache.Avro 活泼的编解码器代码的编解码器部分,使其适用于 1 个块。 (这基本上是任何块 Apache.Avro 占用负 4 个字节,我认为这是我忽略的 Snappy CRC 检查。
  6. 多块失败。我发现它是因为 Apache.Avro 总是在第一个块之后将 deflate 编解码器抛出一个 4096 字节的数组。我把它缩小到阅读大小,然后又做了负 4 大小的事情。成功了。

成功!所以基本上它是复制 deflate 作为 snappy 的模板,将块字节减少 4,然后确保在让 Ironsnappy 解压缩之前将字节数组的大小调整为块字节大小。

public override byte[] Decompress(byte[] compressedData)
{
            int snappySize = compressedData.Length - 4;
            byte[] compressedSnappy_Data = new byte[snappySize];
            System.Array.Copy(compressedData, compressedSnappy_Data, snappySize);

            byte[] result = IronSnappy.Snappy.Decode(compressedSnappy_Data);
            return result;
}
                        if (_codec.GetHashCode() == DataFileConstants.SnappyCodecHash)
                        {
                            byte[] snappyBlock = new byte[(int)_currentBlock.BlockSize];
                            System.Array.Copy(_currentBlock.Data, snappyBlock, (int)_currentBlock.BlockSize);
                            _currentBlock.Data = snappyBlock;
                        }

我没有费心实际使用校验和,因为我不知道如何或不需要?至少不是现在。我完全忽略了压缩功能。

但如果你真的想要我的压缩功能,那就是

        public override byte[] Compress(byte[] uncompressedData)
        {
            return new byte[0];
        }

最简单的解决方案是使用:

ResultModel resultObject = AvroConvert.Deserialize<ResultModel>(byte[] avroObject);

来自https://github.com/AdrianStrugala/AvroConvert

  • 放气
  • 活泼
  • gzip

支持代码