2012-02-23 6 views
3

9ビットバイナリ形式で保存された測定データを読み込み中です。9ビット、10ビット、または11ビットの(正確な)チャンクでデータを読み取り、Objective-C/Cの整数に変換する

101001110 001011100 001101010 101010110 100001011等

データは、古い測定装置からのものである、時には、私は、例えば、チャンクで読み取らなければなりません10ビット、11ビット、または12ビットです。私はいつもファイルの先頭にいくつかのファイル情報があるので、どの整数のサイズを読むべきかを知っています。

しかし、iOS/Objective-Cではバイナリデータを8ビットバイトのサイズにする方法しか知りません。 Int8、int16などに変換し、8ビットまたは16ビットのチャンクを整数に変換します。

NSDataオブジェクトをビット単位で事前定義されたステップでステップ実行するにはどうすればよいですか?

+1

[bithacksページ](http://graphics.stanford.edu/~seander/bithacks.html)のルーチンのほとんどは通常のサイズの数字用に設計されていますが、近い将来、平均的なプログラマーよりも多くのコードを必要とし、このガイドはおそらくあなたの心を暖かくします。 – sarnold

+3

ビットシフトと慎重にあなたがどこにいるのかを追跡する以外に簡単な方法はありません –

+0

これは質問に値するだけではありません。つまり、C言語ではファイル全体を(通常は8ビット長の)文字全体の倍数としてしか読み込むことができないので、あまりできることはありません。 –

答えて

1

独自のデシリアライザを作成する必要があります。たとえば、次のように

@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のビットを数えていることに注目してください。NSUIntegerはメモリから32ビット幅でiOS上にあるため、対処できる最大ファイルサイズは512MBです。 2エクサバイトに移動したい場合は、64ビットのlong longを明示的に使用できます。

次に明らかに追加されるのは、ストリームが終了したかどうかを示すブールゲッターです。

+0

ありがとう。あなたのスニペットコードを試してみます。私のファイルはそれほど大きくはありません。長さがファイルごとに異なりますが(ファイル内では同じですが)整数でいっぱいになった数メガバイトです。 – ChrHansen

0

ファイルが9個、10個、または11個のビット値のいずれかであることが分かっているなら、おそらく私がやるべきことは、これらの長さのデータを抽出する3つの別個のアルゴリズムを書くことです。 "ルーチン。ほとんどの場合、各値に対して8つの可能なアライメントのswitch文を指定することで、指定されたサイズのロジックを処理できます。

関連する問題