【问题标题】:Decompress Data Stream Component: Unknown block type. Stream might be corrupted解压缩数据流组件:未知块类型。流可能已损坏
【发布时间】:2016-03-15 22:15:09
【问题描述】:

我正在尝试解压缩/反序列化保存在 XML 文件属性中的数据流。数据使用 Delphi 的Stream.WriteComponent() 方法进行压缩。它最终会抛出这个错误:

例外: System.IO.InvalidDataException:未知的块类型。流可能已损坏。

首先我使用 XML LINQ 查询检索数据流:

var dataStream = 
(
    from XmlNode xn in nList
    where xn?.Attributes != null 
    && xn?.Attributes["Name"].InnerText == "Columns"
    select xn.Attributes["StreamData"].InnerText
).ToList()[0x0];
if (string.IsNullOrEmpty(dataStream) { return; }

然后我继续获取 XML 属性 InnerText 并将其转换为流数据:

var byteStream = Encoding.UTF8.GetBytes(dataStream);
var memStream = new MemoryStream
(
    byteStream,
    0,
    byteStream.Length,
    true,
    true
);

然后我继续尝试解压缩数据流:

var rslt = Decompress(stream);

这就是 Decompress() 函数的样子:

public static string Decompress(MemoryStream stream)
{
    using (var uncompressed = new MemoryStream())
    using (var compressed = stream)
    using (var ds = new DeflatedStream(compressed, CompressionMode.Decompress))
    {
        ds.CopyTo(uncompressed);
        return Encoding.UTF8.GetString(uncompressed.ToArray());
    }
}

XML 文件看起来与此类似,但不完全相同(我保证它是有效的 xml):

<?xml version="1.0" encoding="UTF-8"?>
<Item Class="Item" Name="Default" GUID="{BC0EE2E4-641F-44DA-A989-F97C58B1828D}">
  <Properties>
    <Property Class="Type" GUID="{3A6C51FB-BE2E-4DBF-B2C5-8EB7C3508529}" Name="Type" group="Item" OrderIndex="0" DecimalPlaces="2">blah</Property>
    <Property Class="Text" GUID="{1119FF79-74C6-42AF-918F-1AF485614D07}" Name="Name" inheritaction="Ignore" required="True" group="Item" OrderIndex="1" DecimalPlaces="2">blahblah</Property>
    <Property Class="Number" GUID="{AF1BC5FD-A4DD-4610-92EE-2F7D7EA4FA64}" Name="OrderIndex" systemhidden="True" OrderIndex="3" DecimalPlaces="2">0</Property>
    <Property Class="Text" GUID="{176382CA-7E00-47C2-8DD3-82A9ED4FB973}" Name="GUID" inheritaction="Ignore" systemlocked="True" systemhidden="True" OrderIndex="4" DecimalPlaces="2">{BC0EE2E4-641F-44DA-A989-F97C58B1828D}</Property>
    <Property Class="Stream" GUID="{833CB9FD-4914-4899-B757-CC9C130E6914}" Name="Columns" OrderIndex="5" DecimalPlaces="2" StreamData="VFBGMB1UcHNjeEVzdGltYXRpbmdUcmVlTGlzdENvbHVtbgZDb2x1bW4MQ2FwdGlvbi5UZXh0BgROYW1lFURhdGFCaW5kaW5nLlZhbHVlVHlwZQYGU3RyaW5nBVdpZHRoAzgBEVBvc2l0aW9uLkNvbEluZGV4AgARUG9zaXRpb24uUm93SW5kZXgCABJQb3NpdGlvbi5CYW5kSW5kZXgCAAlTaG93VW5pdHMIDUlzVW5pdHNDb2x1bW4IAABUUEYwHVRwc2N4RXN0aW1hdGluZ1RyZWVMaXN0Q29sdW1uB0NvbHVtbjIMQ2FwdGlvbi5UZXh0BgtEZXNjcmlwdGlvbhVEYXRhQmluZGluZy5WYWx1ZVR5cGUGBlN0cmluZwVXaWR0aAJsEVBvc2l0aW9uLkNvbEluZGV4AgERUG9zaXRpb24uUm93SW5kZXgCABJQb3NpdGlvbi5CYW5kSW5kZXgCAAlTaG93VW5pdHMIDUlzVW5pdHNDb2x1bW4IAABUUEYwHVRwc2N4RXN0aW1hdGluZ1RyZWVMaXN0Q29sdW1uD1RyZWVMaXN0Q29sdW1uMhNQcm9wZXJ0aWVzQ2xhc3NOYW1lBhJUY3hMYWJlbFByb3BlcnRpZXMZUHJvcGVydGllcy5BbGlnbm1lbnQuSG9yegcNdGFMZWZ0SnVzdGlmeQxDYXB0aW9uLlRleHQGBUNvbG9yFURhdGFCaW5kaW5nLlZhbHVlVHlwZQYGU3RyaW5nBVdpZHRoAiwRUG9zaXRpb24uQ29sSW5kZXgCCBFQb3NpdGlvbi5Sb3dJbmRleAIAElBvc2l0aW9uLkJhbmRJbmRleAIACVNob3dVbml0cwgNSXNVbml0c0NvbHVtbggAAFRQRjAdVHBzY3hFc3RpbWF0aW5nVHJlZUxpc3RDb2x1bW4OVHJlZUxpc3RDb2x1bW4TUHJvcGVydGllc0NsYXNzTmFtZQYSVGN4TGFiZWxQcm9wZXJ0aWVzGVByb3BlcnRpZXMuQWxpZ25tZW50LkhvcnoHDnRhUmlnaHRKdXN0aWZ5DENhcHRpb24uVGV4dAYDUXR5FURhdGFCaW5kaW5nLlZhbHVlVHlwZQYFRmxvYXQOT3B0aW9ucy5Gb290ZXIJBVdpZHRoAmQRUG9zaXRpb24uQ29sSW5kZXgCAhFQb3NpdGlvbi5Sb3dJbmRleAIAElBvc2l0aW9uLkJhbmRJbmRleAIAElN1bW1hcnlGb290ZXIuS2luZAcFc2tTdW0JU2hvd1VuaXRzCQ1Jc1VuaXRzQ29sdW1uCAAAVFBGMB1UcHNjeEVzdGltYXRpbmdUcmVlTGlzdENvbHVtbg9UcmVlTGlzdENvbHVtbjQTUHJvcGVydGllc0NsYXNzTmFtZQYSVGN4TGFiZWxQcm9wZXJ0aWVzGVByb3BlcnRpZXMuQWxpZ25tZW50LkhvcnoHDnRhUmlnaHRKdXN0aWZ5DENhcHRpb24uVGV4dAYKUHJpY2UgRWFjaBVEYXRhQmluZGluZy5WYWx1ZVR5cGUGBUZsb2F0Dk9wdGlvbnMuRm9vdGVyCQVXaWR0aAJkEVBvc2l0aW9uLkNvbEluZGV4AgYRUG9zaXRpb24uUm93SW5kZXgCABJQb3NpdGlvbi5CYW5kSW5kZXgCABJTdW1tYXJ5Rm9vdGVyLktpbmQHBXNrU3VtCVNob3dVbml0cwgNSXNVbml0c0NvbHVtbggAAFRQRjAdVHBzY3hFc3RpbWF0aW5nVHJlZUxpc3RDb2x1bW4PVHJlZUxpc3RDb2x1bW41E1Byb3BlcnRpZXNDbGFzc05hbWUGElRjeExhYmVsUHJvcGVydGllcxlQcm9wZXJ0aWVzLkFsaWdubWVudC5Ib3J6Bw50YVJpZ2h0SnVzdGlmeQxDYXB0aW9uLlRleHQGC1ByaWNlIFRvdGFsFURhdGFCaW5kaW5nLlZhbHVlVHlwZQYFRmxvYXQOT3B0aW9ucy5Gb290ZXIJBVdpZHRoAmQRUG9zaXRpb24uQ29sSW5kZXgCBxFQb3NpdGlvbi5Sb3dJbmRleAIAElBvc2l0aW9uLkJhbmRJbmRleAIAFFN1bW1hcnlGb290ZXIuRm9ybWF0Bg1bIUNVXSMsIyMwLjAwElN1bW1hcnlGb290ZXIuS2luZAcFc2tTdW0JU2hvd1VuaXRzCA1Jc1VuaXRzQ29sdW1uCAAAVFBGMB1UcHNjeEVzdGltYXRpbmdUcmVlTGlzdENvbHVtbg5HcmlkVW50c0NvbHVtbgxDYXB0aW9uLlRleHQGBVVuaXRzFURhdGFCaW5kaW5nLlZhbHVlVHlwZQYGU3RyaW5nD09wdGlvbnMuRWRpdGluZwgFV2lkdGgCMRFQb3NpdGlvbi5Db2xJbmRleAIDEVBvc2l0aW9uLlJvd0luZGV4AgASUG9zaXRpb24uQmFuZEluZGV4AgAJU2hvd1VuaXRzCA1Jc1VuaXRzQ29sdW1uCQ1Vbml0Rm9yQ29sdW1uBgNRdHkAAFRQRjAdVHBzY3hFc3RpbWF0aW5nVHJlZUxpc3RDb2x1bW4PVHJlZUxpc3RDb2x1bW4zE1Byb3BlcnRpZXNDbGFzc05hbWUGElRjeExhYmVsUHJvcGVydGllcxlQcm9wZXJ0aWVzLkFsaWdubWVudC5Ib3J6Bw50YVJpZ2h0SnVzdGlmeQxDYXB0aW9uLlRleHQGCUNvc3QgRWFjaBVEYXRhQmluZGluZy5WYWx1ZVR5cGUGBUZsb2F0Dk9wdGlvbnMuRm9vdGVyCQVXaWR0aAJkEVBvc2l0aW9uLkNvbEluZGV4AgQRUG9zaXRpb24uUm93SW5kZXgCABJQb3NpdGlvbi5CYW5kSW5kZXgCABRTdW1tYXJ5Rm9vdGVyLkZvcm1hdAYNWyFDVV0jLCMjMC4wMBJTdW1tYXJ5Rm9vdGVyLktpbmQHBXNrU3VtCVNob3dVbml0cwgNSXNVbml0c0NvbHVtbggAAFRQRjAdVHBzY3hFc3RpbWF0aW5nVHJlZUxpc3RDb2x1bW4PVHJlZUxpc3RDb2x1bW42E1Byb3BlcnRpZXNDbGFzc05hbWUGElRjeExhYmVsUHJvcGVydGllcxlQcm9wZXJ0aWVzLkFsaWdubWVudC5Ib3J6Bw50YVJpZ2h0SnVzdGlmeQxDYXB0aW9uLlRleHQGCE1hcmt1cCAlFURhdGFCaW5kaW5nLlZhbHVlVHlwZQYFRmxvYXQOT3B0aW9ucy5Gb290ZXIJBVdpZHRoAkMRUG9zaXRpb24uQ29sSW5kZXgCBRFQb3NpdGlvbi5Sb3dJbmRleAIAElBvc2l0aW9uLkJhbmRJbmRleAIAElN1bW1hcnlGb290ZXIuS2luZAcFc2tTdW0JU2hvd1VuaXRzCA1Jc1VuaXRzQ29sdW1uCAAA"/>

  </Properties>
</Item>

【问题讨论】:

  • 在没有看到创建文件的代码或示例文件的情况下,我们不得不猜测您实际做了什么
  • 我用 xml 更新了它
  • 我感觉这将归结为 zlib 标头不兼容的问题。解码 base64 并检查标头。获取 Delphi 代码会有所帮助!
  • 很遗憾,我无法访问 Delphi 代码
  • 我确实为 zlib .net 添加了一个 nuget 但没有使用它,我对此有点困惑

标签: c# xml stream deserialization


【解决方案1】:

由于 XML 是一个字符串,并且几乎可以肯定解压缩需要二进制数据作为输入,因此 StreamData 属性的值必须是二进制数据的 ASCII/字符串编码表示。这可以使用简单的 bin-2-hex 表示法,但从问题中提供的示例来看,它看起来更有可能是 base64 或类似的。

提供 XML 的人应该能够为您确认编码。

无论如何,我们可以相当肯定StreamData 必须采用字符串编码形式,否则二进制数据将包含导致无效 XML 文件的值(例如值为 0 的字节等)

既然如此,那么您的问题是Encoding.UTF8.GetBytes() 将其传递的数据简单地解释为字节数组。也就是说,它期望给定的字节是有效的 UTF8 编码字符串的一部分。它做任何从十六进制字符到二进制字节等的转换。

也就是说,使用一个非常简单的示例,如果您的 StreamData 是一个值为 "000102" 的字符串,那么您的代码当前将生成一个 byteStream,其内容由 6(六)个字节组成,值为如下:

StreamData :  '0' '0' '0' '1' '0' '2'
bytes      : [30][30][30][31][30][32]    (hexadecimal byte values)

当您可能期望的是一个 3(三)个字节的流,其值对应于 StreamData,如下所示:

StreamData : '00''01''02'
bytes      : [00][01][02]                (hexadecimal byte values)

即您需要将StreamData 字符串正确解码为其内存中的二进制表示,然后再将其传递给当前抱怨的 Decompress() 例程,因为它提供的二进制数据无效, 压缩数据。

您需要在StreamData 中确认二进制数据的编码并应用适当的解码以获得该数据的二进制表示,然后再将其传递给 Decompress() 例程,而不是原始/原始字符串表示。

【讨论】:

  • 我唯一确定的是,无论谁压缩它,都通过 Delphi/Pascal 使用了 Stream.WriteComponent。谢谢-我会试试你推荐的。
  • 这里是streamdata属性的一个相当大的块:StreamData =“Bhl0bEVzdGltYXRpbmcudGxFc3RpbWF0aW5nBgtUY3hUcmVlTGlzdAIAAgoGBUJhbmRzBhBUY3hUcmVlTGlzdEJhbmRzAgACAQYFQmFuZDAGD1RjeFRyZWVMaXN0QmFuZAIFBgdDYXB0aW9uAggGAAYMUmVhbE1pbldpZHRoAgYCFAYJUmVhbFdpZHRoAgYCAAYHVmlzaWJsZQIIBgRUcnVlBgVJbmRleAIGAgACAAYGQ29sdW1uBh1UcHNjeEVzdGltYXRpbmdUcmVlTGlzdENvbHVtbgILBgdWaXNpYmxlAggGBFRydWUGBUluZGV4AgYCAAYJTGluZUNvdW50AgYCAQYIQ29sSW5kZXgCBgIABghSb3dJbmRleAIGAgAGCUJhbm 跨度>
  • 如果有帮助,我将流数据属性放在我的示例中
  • 在我看来确实像 base64。提供 XML 文件的人应该能够为您确认。 :)
  • 嘿,所以我终于让它像你推荐的那样工作,但现在我不知道如何处理它返回的内容:“TPF0TpscxEstimatingTreeListColumnColumnCaption.TextNameDataBinding.ValueTypeStringWidth8Position.ColIndex”它只是一个乱码字符串 ...
猜你喜欢
  • 1970-01-01
  • 2021-01-19
  • 1970-01-01
  • 2012-11-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多