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
È stato utile?

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);
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top