2012-08-16 14 views
5

Ich habe das Lesen SWF format auf der Adobe-Website zur Verfügung und es wird erwähnt, dass Raum, um zu sparen, werden variable Bits zum Speichern von ganzen Zahlen oder Schwimmern verwendet (Seite 17 im pdf)Lesen Bit-ausgerichteten Daten

Ich habe hat immer mit Byte-ausgerichteten Daten gearbeitet, so dass man sich keine Gedanken über Dateien gemacht hat, die Bit-ausgerichtet sind oder eine variable Ausrichtung haben, bei der die Information in jedem Byte gespeichert wird.

So haben Sie zum Beispiel eine Struktur, die vier 13-Bit-Ganzzahlen sequenziell gespeichert (anstatt sie als vier 16-Bit-Ganzzahlen speichern).

Die ersten 13 Bit sind die erste Ganzzahl, die nächsten 13 Bit sind die zweite Ganzzahl und so weiter. Er puffert das letzte Byte, das geeignet ist, um die Struct-Byte-Ausrichtung mit dem Rest der Datei auszurichten, so dass 52 Bits zu 56 Bits aufgefüllt werden würden, was 7 Bytes erfordert, um diese vier ganzen Zahlen im Gegensatz zu 8 Bytes zu speichern.

  • Wie gehe ich an diese Art von Problem heran?
  • Wie kann ich mit einem Strom von Bytes auf der Bit-Ebene arbeiten?
  • Kann ich etwas verwenden, um die Arbeit mit diesen Daten zu erleichtern?

Ich stelle mir vor, die Lösung läuft auf die Verwendung von Bit-Operationen auf Byte-Arrays.

Eine Beispiellösung zum Analysieren der vier 13-Bit-Ganzzahlen wäre auch gut, um die Verwendung Ihrer vorgeschlagenen Methode zu demonstrieren.

+0

..wenn ich kann nicht geben Sie eine vollständige Antwort, vielleicht zeigt Ihnen zumindest auf BitArray helfen :) –

+1

In der Regel hält der Ansatz einen Puffer von Bits in einem Uint oder ulong, Extrahieren, was Sie brauchen und Verschieben eines neuen Eingangsbytes, wenn nicht genügend Bits im Puffer vorhanden sind. – harold

Antwort

3

Es gibt zwei Möglichkeiten, damit umzugehen, die ich kenne. Die erste ist, es manuell zu tun - mit bitweisen Operatoren, Division, Modulus usw. auf Byte-Arrays [oder Integer/ulong usw., wenn Sie gelangweilt waren]. IsBitSet Example

Der andere Weg ist ein BitArray - die meisten dies für Sie Griffe :)


Es wäre schön, ein Beispiel dafür, wie genau 13..25 BitArray Griffe bekommen Bits hinzufügen, wie ein Int, als wäre das die primäre Operation. Auf den ersten Blick sehe ich nur eine Schleife.

Fein ... Ich schrieb einen schnellen & schmutzig Test Proof of Concept:

var rnd = new Random(); 
//var data = Enumerable.Range(0, 10).ToArray(); 
var data = Enumerable.Range(0, 10).Select(x => rnd.Next(1 << 13)).ToArray(); 

foreach (var n in data) Console.WriteLine(n); 

Console.WriteLine(new string('-', 13)); 

var bits = new BitArray(data.Length * 13); 

for (int i = 0; i < data.Length; i++) 
{ 
    var intBits = new BitArray(new[] { data[i] }); 
    for (int b = 12; b > -1; b--) 
    { 
     bits[i * 13 + b] = intBits[b]; 
     Console.Write(intBits[b] ? 1 : 0); 
    } 
    Console.WriteLine(); 
} 
Console.WriteLine(new string('-', 13)); 

for (int i = 0; i < bits.Length/13; i++) 
{ 
    int number = 0; 
    for (int b = 12; b > -1; b--) 
     if (bits[i * 13 + b]) 
      number += 1 << b; 

    Console.WriteLine(number); 
} 
Console.ReadLine(); 

Welche Ausgänge:

910 
3934 
7326 
7990 
7712 
1178 
6380 
3460 
5113 
7489 
------------- 
0001110001110 
0111101011110 
1110010011110 
1111100110110 
1111000100000 
0010010011010 
1100011101100 
0110110000100 
1001111111001 
1110101000001 
------------- 
910 
3934 
7326 
7990 
7712 
1178 
6380 
3460 
5113 
7489 

Das Bit-Array nicht viel tun, außer zu vereinfachen den Zugriff auf - Es ist immer noch ziemlich manuell.Ich erwarte, dass Sie würden Ihre eigenen Klassen schreiben, um dies einfach und es ordentlich und wiederverwendbar machen - zum Beispiel hier ist ein anderes schnelles Konzept:

//Improved to take sign into account. 
//Sign is in addition to bits allocated for storage in this version. 
//Stored as {sign}{bits} 
//E.g. -5, stored in 3 bits signed is: 
//  1 101 
//E.g. 5, stored in 3 bits [with sign turned on] 
//  0 101 
//E.g. 5, stored in 3 bits no sign 
//   101 
//This may differ from your exiting format - e.g. you may use two's compliments. 
static void Main(string[] args) 
{ 
    int bitsPerInt = 13; 

    //Create your data 
    var rnd = new Random(); 
    //var data = Enumerable.Range(-5, 10).ToArray(); 
    var data = Enumerable.Range(0, 10).Select(x => rnd.Next(-(1 << bitsPerInt), 1 << bitsPerInt)).ToArray(); 

    var bits = new BitSerlializer(); 

    //Add length header 
    bits.AddInt(data.Length, 8, false); 
    foreach (var n in data) 
    { 
     bits.AddInt(n, bitsPerInt); 
     Console.WriteLine(n); 
    } 

    //Serialize to bytes for network transfer etc. 
    var bytes = bits.ToBytes(); 

    Console.WriteLine(new string('-', 10)); 
    foreach (var b in bytes) Console.WriteLine(Convert.ToString(b, 2).PadLeft(8, '0')); 
    Console.WriteLine(new string('-', 10)); 

    //Deserialize 
    bits = new BitSerlializer(bytes); 
    //Get Length Header 
    var count = bits.ReadInt(8, false); 
    for (int i = 0; i < count; i++) 
     Console.WriteLine(bits.ReadInt(bitsPerInt)); 

    Console.ReadLine(); 
} 

public class BitSerlializer 
{ 
    List<byte> bytes; 
    int Position { get; set; } 

    public BitSerlializer(byte[] initialData = null) 
    { 
     if (initialData == null) 
      bytes = new List<byte>(); 
     else 
      bytes = new List<byte>(initialData); 
    } 

    public byte[] ToBytes() { return bytes.ToArray(); } 

    public void Addbit(bool val) 
    { 
     if (Position % 8 == 0) bytes.Add(0); 
     if (val) bytes[Position/8] += (byte)(128 >> (Position % 8)); 
     Position++; 
    } 

    public void AddInt(int i, int length, bool isSigned = true) 
    { 
     if (isSigned) Addbit(i < 0); 
     if (i < 0) i = -i; 

     for (int pos = --length; pos >= 0; pos--) 
     { 
      var val = (i & (1 << pos)) != 0; 
      Addbit(val); 
     } 
    } 

    public bool ReadBit() 
    { 
     var val = (bytes[Position/8] & (128 >> (Position % 8))) != 0; 
     ++Position; 
     return val; 
    } 

    public int ReadInt(int length, bool isSigned = true) 
    { 
     var val = 0; 
     var sign = isSigned && ReadBit() ? -1 : 1; 

     for (int pos = --length; pos >= 0; pos--) 
      if (ReadBit()) 
       val += 1 << pos; 

     return val * sign; 
    } 
} 
+0

Es wäre nett, ein Beispiel hinzuzufügen, wie genau BitArray die Bits 13..25 als int behandelt, da dies die primäre Operation wäre. Auf den ersten Blick sehe ich nur eine Schleife. –

+0

Whoa! Ich bin beeindruckt. Ich glaube, dies betrifft nicht das Zeichen und seine Erweiterung, auch nicht sicher, ob die Leistung auch in Betracht kommt - Keikoku erwähnte es nicht, also wahrscheinlich nicht. Ansonsten ein hervorragendes Beispiel für eine umfassende Antwort. Das ist +1. –

+0

@EugeneRyabtsev - guter Fang, in meiner zweiten Version im Zeichen hinzugefügt. – NPSF3000

3

Auf der anderen Seite, Byte-Array-basierter Ansatz weitergehen könnte:

int extend(uint raw, int bits) 
    { 
     int sh = 32 - bits; 
     int x = (int)raw << sh; // puts your sign bit in the highest bit. 
     return x >> sh; // since x is signed this is an arithmatic signed shift 
    } 

    int read(byte[] data, int pos, int bits, bool signed) 
    { 
     int fbi = pos/8; // first byte index 
     int lbi = (pos + bits - 1)/8; // last byte index 
     int cnt = lbi - fbi + 1; // bytes spanned 
     if (cnt > 3 || lbi >= data.Length) { throw new ArgumentException(); } 

     uint raw = (uint)(
      (data[fbi] << (24 + pos % 8)) + 
      (cnt < 2 ? 0 : data[fbi + 1] << (16 + pos % 8)) + 
      (cnt < 3 ? 0 : data[fbi + 2] << (8 + pos % 8)) 
      ) >> (32 - bits); 
     return signed ? extend(raw, bits) : (int)raw; 
    } 

Test für diese:

byte[] test = { 0x55, 0xAA, 0x10 }; 

    string s = ""; 
    s += read(test, 0, 8, false) + "\r\n"; 
    s += read(test, 0, 8, true) + "\r\n"; 
    s += read(test, 8, 8, false) + "\r\n"; 
    s += read(test, 8, 8, true) + "\r\n"; 
    s += read(test, 4, 8, false) + "\r\n"; 
    s += read(test, 7, 9, true) + "\r\n"; 
    s += read(test, 7, 10, true) + "\r\n"; 
    s += read(test, 7, 11, true) + "\r\n"; 
    s += read(test, 7, 12, true) + "\r\n"; 
    s += read(test, 7, 13, true) + "\r\n"; 
    s += read(test, 7, 14, true) + "\r\n"; 
    s += read(test, 7, 15, true) + "\r\n"; 
    s += read(test, 7, 16, true) + "\r\n"; 
    s += read(test, 7, 17, true) + "\r\n"; 
    s += read(test, 18, 2, true) + "\r\n"; 
    s += read(test, 18, 3, true) + "\r\n"; 
    s += read(test, 23, 1, true) + "\r\n"; 
    s += read(test, 23, 2, true) + "\r\n"; 

der Test baut die Zeichenfolge wie folgt aus:

85 
    85 
    170 
    -86 
    90 
    -86 
    -172 
    -344 
    -688 
    -1375 
    -2750 
    -5500 
    -11000 
    -22000 
    1 
    2 
    0 

löst dann eine Ausnahme in der letzten Zeile aus.

+0

Interessantes System. Fehlende Schreibfähigkeit ... und sollte verallgemeinert werden, um mit Bitfolgen beliebiger Länge umgehen zu können [damit Sie einfach Funktionen schreiben können, die mehr als int serialisieren]. – NPSF3000