Чтение данных в 9-, 10- или 11-битных (точных) фрагментах и ​​преобразование в целое число в Objective-C / C - PullRequest
3 голосов
/ 24 февраля 2012

Я читаю данные измерений, которые сохраняются в 9-битной двоичной форме без пробелов, например,

101001110 001011100 001101010 101010110 100001011 и т. Д.

Данные взяты из старого измерительного оборудования, и иногда мне приходится читать порциями, например, 10, 11 или 12 бит. Я всегда буду знать, какой целочисленный размер читать, так как в начале файла есть некоторая информация о файле.

Но в iOS / Objective-C я знаю только, как получить двоичные данные размером до 8 бит, например, Int8, int16 и т. Д. И преобразовать эти 8- или 16-битные блоки в целые числа.

Как мне пройти, скажем, NSData-объект в побитовых предварительно определенных шагах?

Ответы [ 2 ]

1 голос
/ 24 февраля 2012

Вы должны написать свой собственный десериализатор.Например:

@interface CHBinaryStream

// init with an NSData from which values will be read
- (id)initWithData:(NSData *)data;

// e.g. readBits:9 will assemble 9 bits from the data stream,
// return them in the low 9 bits of an NSUInteger. If you
// ask for more bits than an NSUInteger can store then they'll
// just drop off the end. This will also advance the read pointer
// by 9 bits
- (NSUInteger)readBits:(int)numberOfBits;

@end

И:

@implementation CHBinaryStream
{
     NSData *sourceData;
     NSUInteger readPointer;
}

- (id)initWithData:(NSData *)data
{
    self = [super init];

    if(self)
    {
        sourceData = [data retain];
    }

    return self;
}

- (void)dealloc
{
    [sourceData release], sourceData = nil;
    [super dealloc];
}

- (NSUInteger)readBit
{
    // we'll just return a stream of 0s if we
    // go past the end of the source data
    if((readPointer >> 3) >= [sourceData length]) return 0;

    // otherwise we'll read the byte at:
    //
    //    sourceData >> 3
    //
    // and return the bit at:
    //
    //    sourceData & 7
    //
    // (where for our purposes, the 0th bit in a byte
    // is the most significant)
    uint8_t sourceByte = ((uint8_t *)[sourceData bytes])[sourceData >> 3];

    sourceByte <<= sourceData&7; // the bit we want is now where the MSB was
    sourceByte >>= 7;            // the bit we want is now in the LSB
    sourceByte &= 1;             // this clears all the other bits

    /*

         Alternative: (sourceByte >> ((sourceData & 7) ^ 7))&1;

    */

    // advance the read pointer, and then return the value
    readPointer++;

    return sourceByte;
}


- (NSUInteger)readBits:(int)numberOfBits
{
     NSUInteger result = 0;

     // shift in the required number of bits;
     // since we're going to get the most significant
     // bits first, we add incoming bits in the least
     // significant location and shift upward

     while(numberOfBits--)
         result = (result << 1) | [self readBit];

     return result;
}

@end

Все не проверено, но, надеюсь, правильно.Обратите внимание, что я считаю биты в NSUInteger, который из памяти имеет 32-битную ширину под iOS, поэтому максимальный размер файла, с которым он может справиться, составляет 512 МБ.Вы можете явно использовать длину 64 бита, если хотите перейти к 2 экзабайтам.

Очевидным следующим шагом, который нужно добавить, будет логический метод получения завершения потока.

0 голосов
/ 24 февраля 2012

Если вы знаете, что файл содержит все 9, все 10 или все 11-битные значения, то, вероятно, я бы написал три отдельных алгоритма для извлечения данных такой длины против попыток написать «универсальный» рутина. В большинстве случаев вы можете обрабатывать логику для заданного размера, используя инструкцию switch для 8 возможных выравниваний для каждого значения.

...