2013-02-05 13 views
7

Mam macierz o stałej długości, która ma 1250 bajtów długości. Może zawierać następujące typy danych:Parsująca tablica bajtów, która zawiera różne typy danych.

  • Obiekt A, który składa się z 5 bajtów. Pierwszy bajt zawiera literę "A" o numerze , a kolejne cztery bajty przechowują liczbę całkowitą od 1 do 100000.

  • Obiekt B, który składa się z 2 bajtów. Pierwszy bajt zawiera literę "B", a następny bajt zawiera liczbę całkowitą od 1 - 100.

  • Obiekt C, który składa się z 50 bajtów. Wszystkie 50 bajty są używane do przechowywania ciąg ASCII zakodowany które tylko składać się z numerów oraz następujące znaki: - + (i)

nie wiem ilu z każdego typu obiektu są w tablicy bajtów, ale wiem, że są one zgrupowane razem (Obiekt B, Obiekt B, Obiekt A, Obiekt A, Obiekt A, Obiekt C itd.). W większości przypadków, gdy parsuję tablicę bajtów, tablica zawiera dane jednego typu (wszystkie obiekty to na przykład obiekt A), więc wiem dokładnie, z ilu bajtów składa się każdy element i po prostu przechodzę przez tablicę przetwarzającą bajty . W tym przypadku mam trzy różne typy danych, które mają różne długości. Myślałam, że muszę zrobić coś takiego:

int offset = 0; 
while (offset <= 1250) 
{ 
    string objectHeader = Encoding.ASCII.GetString(byteArray, offset, 1); 

    if (objectHeader.Equals("A")) 
    { 
     // read 4 more bytes and then convert into int value (1 - 100000) 
     index += 5; 
    } 
    else if (objectHeader.Equals("B")) 
    { 
     // read 1 more byte and then convert into int value (1 - 100) 
     index += 2; 
    } 
    else 
    { 
     // read 49 more bytes and then convert into a string 
     index += 50; 
    } 
} 

Czy istnieje lepszy sposób to zrobić?

+2

Co jeśli łańcuch zawarty w instancji klasy C zaczyna się od znaku "B"? Jak będziesz wiedział, jak to rozpakować? Musisz wyemitować rodzaj informacji o typie. – Matt

+2

Czy przechowujesz te informacje, czy te wcześniejsze dane próbujesz wczytać? Pytam, ponieważ istnieją znacznie łatwiejsze sposoby przechowywania danych niż tablice bajtów. – sircodesalot

+0

@Matt Nie udało mi się powiedzieć, że ciąg reprezentowany przez Obiekt C będzie składał się wyłącznie z liczb. Jeśli tak nie jest, jakie informacje o typie sugerujesz? – user685869

Odpowiedz

7

dobrze, nie wydaje się być trochę zamieszania z offsetem i indeks, może powinieneś być za pomocą pętli for:

for(int index = 0; index < 1250; index++) 
{ 
    switch(byteArray[index]) 
    { 
     case (byte)'A': 
      index++; 
      int value = BitConverter.ToInt32(byteArray, index); 
      index += 4; 
      break; 

     case (byte)'B': 
      index++; 
      // Read the next byte as integer. 
      int value = (int)byteArray[index]; 
      index++; 
      break; 

     case (byte)'C': // string. 
      index++; 
      // Read the next 49 bytes as an string. 
      StringBuilder value = new StringBuilder(49); 
      for(int i = index; i < index + 49; index++) 
      { 
       if (byteArray[i] == 0) break; 
       value.Append(Converter.ToChar(byteArray[i])); 
      } 
      index+= 49; 
      break; 

     case 0: // Finished. 
      index = 1250; 
      break; 
     default: 
      throw new InvalidArgumentException("Invalid byte array format"); 
    } 
} 

Jak widzisz, czy nie ma już obiektów? W moim przykładzie sugeruję, aby kończyło się na '\ 0'.

Powodzenia w misji.

+0

Dzięki za sugestię. Mam zaktualizowane moje oryginalne pytanie, aby wyjaśnić, że ciąg przechowywany w Object C będzie składał się tylko z cyfr i znaków - + (i) – user685869

+0

Nie mam dobrego sposobu na stwierdzenie, że nie ma więcej obiektów bez przetwarzania całego bajtu szyk. – user685869

+0

Prawdopodobnie nie musisz analizować całej tablicy bajtów, ponieważ uderzysz w obiekt, który nie pasuje do twojego formatu. EG: Obiekt B większy niż 100; Obiekt C zawiera znak inny niż ASCII i znaki: - + (i). Mogę sobie wyobrazić, że jeśli jest to urządzenie sprzętowe, po prostu wstawi je za pomocą 0x00s, więc trafisz 50-znakowy ciąg, który nie zostanie sprawdzony i złamany. – Cashley

2
 int offset = 0; 
     while (offset <= 1250) 
     { 

     switch (byteArray[offset]) 
     { 
      case (byte)'A': 
      //read other data .. 
      offset += 5; 
      break; 
      case (byte)'B': 
      //read other data .. 
      offset += 2; 
      break; 
      case (byte)'C': 
      //read other data .. 
      offset += 50; 
      break; 
      default: 
      //error 
      break; 
     } 
     } 

Albo inny wariant z binarnym czytelnika:

 var reader = new BinaryReader(new MemoryStream(byteArray), Encoding.ASCII); 
     while (reader.BaseStream.Position < reader.BaseStream.Length) 
     { 
     switch(reader.ReadChar()) 
     { 
      case 'A': 
      { 
       var i = reader.ReadInt32(); 
       return new TypeA(i); 
      } 
      break; 
      case 'B': 
      { 
       var i = reader.ReadByte(); 
       return new TypeB(i); 
      } 
      break; 
      case 'C': 
      { 
       var chars = reader.ReadChars(49); 
       return new TypeC(new string(chars.TakeWhile(ch => ch != 0).ToArray())); 
      } 
      break; 
     } 

     }