Serializzare int array in binario / base64 forma per essere usato in VTK
Domanda
Sto scrivendo la mia scrittore per VTK file XML utilizzando F#.Il file VTK ha bisogno di un base64 codifica di dati binari, insieme con una intestazione, come descritto qui.
...Così i dati binari deve essere codificato in base64.Inoltre, c'è un'intestazione anteposto ai dati;si tratta di un numero intero a 32 bit contenente i dati lunghezza (in byte).Questa intestazione è codificato separatamente.Così in pseudocodice, i dati di output sarà simile a questa (sempre senza spazi o interruzioni di riga!)
Il mio codice simile a:
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
Il risultato, tuttavia, non è corretto.Per i seguenti input:
toBase64 [| 1; 2; 3; 4 |]
ParaView (scritto in C++) visualizza gli intervalli di -256 a 511 invece di 1 a 4.Non si vede alcun evidente bug nel mio codice?
Modifica:I miei dati con codifica base64, assomiglia a questo:
LAAAAAABAAAA/////wEAAAAAAAAADwEAAAAEAAAACAEAAAACAaaaawaaaaqaaaal
EDIT 2:Allego la mia soluzione che prende un array di float e convertirlo in un array di Byte, comprimere utilizzando Ionic.Zip.dll ZLib e convertirlo in una stringa base64.La funzione funziona bene con VTK file 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
Soluzione
Non so nulla circa il formato VTK, ma sarei molto sorpreso se BinaryFormatter
era la strada da percorrere - Penso che genera qualche codifica proprietaria dei tipi .NET e include un sacco di informazioni aggiuntive (che il formato VTK non ha bisogno, a meno che non si basa su binario NET serializzazione).
Credo che scrivere i valori interi direttamente nel flusso sarebbe un'idea migliore. Come ho detto, non so il formato, ma mi aspetto che qualcosa del genere sarebbe più vicino a quello che vi serve:
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
Altri suggerimenti
Perché Paraview display da 1 a 4? BinaryFormatter
è una bestia complessa che comprende un sacco di ulteriori metadati .NETTO tipi.Se è possibile chiarire in che modo si desidera che questo codificato, può forse aiutare.Per esempio, se il vostro 1-4 byte si dovrebbe essere in grado di base-64 codificare direttamente a loro.Se vogliono essere trattati come numeri interi, si avrebbe bisogno di codificarli in byte prima.
In definitiva, senza un mappa la codifica di regole (tra cui endianness ecc) è difficile dare una risposta definitiva, ma BinaryFormatter
quasi certamente non lo è.
Sono molto familiarità con personalizzata codifica binaria, e sono felice di offrire maggiore assistenza/guida, ma ho davvero bisogno di maggiori informazioni in termini di ciò che il protocollo è in attesa.
Per esempio, l'utilizzo di C# (scusa, il mio F#-pippo è limitata), e supponendo little-endian a lunghezza fissa integer a 32 bit di codifica di tutto:
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);
}