0

我正在使用 F# 为 VTK XML 文件编写自己的编写器。VTK 文件需要二进制数据的 base64 编码,以及此处描述的标头。

...所以二进制数据必须是 base64 编码的。此外,数据前面还有一个标头;它是一个 32 位整数,包含数据长度(以字节为单位)。此标头是单独编码的。所以在伪代码中,数据输出看起来像这样(总是没有空格或换行符!)

我的代码如下所示:

let toBase64 (v: int []) =
  use ms = new System.IO.MemoryStream()
  let s = System.Runtime.Serialization.Formatters.Binary.BinaryFormatter()
  s.Serialize(ms, v)
  let b = ms.ToArray()
  let len = System.BitConverter.GetBytes b.Length
  System.Convert.ToBase64String len + System.Convert.ToBase64String b

然而,结果是不正确的。对于以下输入:

toBase64 [| 1; 2; 3; 4 |]

ParaView(用 C++ 编写)显示范围 -256 到 511 而不是 1 到 4。您在我的代码中看到任何明显的错误吗?

编辑:我的 base64 编码数据如下所示:

LAAAAAAAAAAAA/////wEAAAAAAAAADwEAAAAEAAAACAEAAAACAAAAAAwAAAAQAAAAL

编辑 2:我附上了我的解决方案,它采用浮点数组并将其转换为字节数组,使用 Ionic.Zip.dll ZLib 对其进行压缩并将其转换为 base64 字符串。该函数适用于 VTK XML 文件。

let toZlib (v: float []) =
  use msSinkCompressed = new System.IO.MemoryStream()
  let zOut = new ZlibStream(msSinkCompressed, CompressionMode.Compress, CompressionLevel.Default, true)
  for i in v do 
    let bytes = System.BitConverter.GetBytes i
    zOut.Write(bytes, 0, bytes.Length)
  zOut.Flush()
  zOut.Close()
  let comprBytes = msSinkCompressed.ToArray()
  let header =
    let blocks = System.BitConverter.GetBytes 1
    let len = System.BitConverter.GetBytes (v.Length * 8)
    let comprLen = System.BitConverter.GetBytes comprBytes.Length
    Array.append(Array.append (Array.append blocks len) len) comprLen
  System.Convert.ToBase64String header + System.Convert.ToBase64String comprBytes
4

2 回答 2

1

我对 VTK 格式一无所知,但如果BinaryFormatter是这样的话,我会感到非常惊讶 - 我认为它会生成一些 .NET 类型的专有编码,并且它包含许多附加信息(VTK 格式不t 需要,除非它基于二进制 .NET 序列化)。

我认为将整数值直接写入流会是一个更好的主意。正如我所说,我不知道格式,但我希望这样的东西更接近你的需要:

let toBase64 (v: int []) = 
  use ms = new System.IO.MemoryStream() 
  for i in v do 
    let bytes = System.BitConverter.GetBytes i
    ms.Write(bytes, 0, bytes.Length)
  let b = ms.ToArray() 
  let len = System.BitConverter.GetBytes b.Length 
  System.Convert.ToBase64String len + System.Convert.ToBase64String b 
于 2010-11-22T12:36:24.537 回答
0

为什么 Paraview 会显示 1 到 4?BinaryFormatter是一个复杂的野兽,其中包含许多有关 .NET 类型的附加元数据。如果您可以阐明您希望如何编码,它可能会有所帮助。例如,如果您的 1-4 是字节,您应该能够直接对它们进行 base-64 编码。如果要将它们视为整数,则需要先将它们编码为字节。

最终,如果没有详细的编码规则(包括字节序等),很难给出明确的答案,但BinaryFormatter几乎可以肯定不是。

我对自定义二进制编码非常熟悉,我很乐意提供更多帮助/指导,但我确实需要更多关于协议期望的信息。

例如,使用 C#(对不起,我的 F#-foo 是有限的),并假设始终采用 little-endian 固定长度 32 位整数编码:

static void Main() {
    string s = Encode(new int[] { 1, 2, 3, 4 });
}
static string Encode(int[] data) {
    byte[] buffer = new byte[data.Length * 4];
    int offset = 0;
    for(int i = 0 ; i < data.Length ; i++) {
        int value = data[i];
        buffer[offset++] = (byte)value;
        buffer[offset++] = (byte)(value >> 8);
        buffer[offset++] = (byte)(value >> 16);
        buffer[offset++] = (byte)(value >> 24);
    }
    byte[] header = new byte[4];
    int len = buffer.Length;
    header[0] = (byte)len;
    header[1] = (byte)(len >> 8);
    header[2] = (byte)(len >> 16);
    header[3] = (byte)(len >> 24);
    return Convert.ToBase64String(header) + Convert.ToBase64String(buffer);
}
于 2010-11-22T12:34:42.070 回答