0

非ブロッキング IO を使用してネットワーク セッションから以前に取得したバイト配列にいくつかのデータがあります (複数のチャネルを容易にするため)。

データのフォーマットは基本的に

varint: length of text
UTF-8: the text

テキストの開始位置が未定であることを考慮して、テキストを効率的に抽出する方法を見つけようとしています (varint の長さは可変であるため)。私は本当に近いものを持っていますが、1つの小さなニグルのために、ここに行きます:

import com.clearspring.analytics.util.Varint;
// Some fields for your info
private final byte replyBuffer[] = new byte[32768];
private static final Charset UTF8 = Charset.forName ("UTF-8");

// ...
  // Code which extracts the text
    ByteArrayInputStream byteInputStream = new ByteArrayInputStream(replyBuffer);
    DataInputStream inputStream = new DataInputStream(byteInputStream);
    int textLengthBytes;

    try {
      textLengthBytes = Varint.readSignedVarInt (inputStream);
    }
    catch (IOException e) {
     // I don't think we should ever get an IOException when using the
     // ByteArrayInputStream class
       throw new RuntimeException ("Unexpected IOException", e);
    }
    int offset = byteInputStream.pos(); // ** Here lies the problem **
    String textReceived = new String (replyBuffer, offset, textLengthBytes, UTF8); 

バッファ内のテキスト オフセットが byteInputStream.pos() によって示されるという考え方です。ただし、そのメソッドは保護されています。

varint をデコードした後にテキストの「残り」を取得する唯一の方法は、それをすべて別のバッファにコピーするものを使用することですが、それは私にとってはかなり無駄に思えます。

基になるバッファーから直接文字列を構築することは問題ないはずです。これ以降は、byteInputStream または inputStream の状態を気にしなくなるからです。だから私は、オフセットを計算する方法を見つけようとしています。別の言い方をすれば、Varint.readSignedVarInt が消費したバイト数です。おそらく、Varint.readSignedVarInt によって返される整数値からエンコーディングで使用されるバイト数に変換する効率的な方法があるでしょうか?

4

1 に答える 1

1

バイト配列内の文字列のオフセットを見つけるには、いくつかの方法があります。

  • ByteArrayInputStreamフィールドにアクセスできるサブクラスを作成できますpos。サブクラスが使用できるように、アクセスが保護されています。
  • より一般的に適用できるものが必要な場合は、FilterInputStream読み取られたバイト数をカウントする のサブクラスを作成します。これはより多くの作業であり、おそらく努力する価値はありません。
  • をエンコードするバイト数をカウントしますvarint。多くても5つです。

    int offset = 0; while (replyBuffer[offset++] < 0);
    
  • をエンコードするのに必要なバイト数を計算しますvarint。各バイトは 7 ビットをエンコードするため、最上位の 1 ビットの位置を取得して 7 で割ることができます。

    // "zigzag" encoding required since you store the length as signed
    int textLengthUnsigned = (textLengthBytes<<2) ^ (textLengthBytes >> 31);
    int offset = (31 - Integer.numberOfLeadingZeros(textLengthUnsigned))/7 + 1
    
于 2013-11-14T11:26:16.097 に答える