Java Выполняет итерацию битов в массиве байтов

#java #byte #bit

Вопрос:

Как я могу перебирать биты в массиве байтов?

Комментарии:

1. Ты не можешь. По крайней мере, не напрямую. Что вы пытаетесь сделать, возможно, есть лучший способ. Массив байтов содержит набор байтов.

2. И еще раз, я хотел бы, чтобы в java.util.BitSet был конструктор byte [].

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

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

Ответ №1:

Вам пришлось бы написать свою собственную реализацию Iterable<Boolean> , которая занимала массив байтов, а затем создавала Iterator<Boolean> значения, которые запоминали текущий индекс в массив байтов и текущий индекс в текущем байте. Тогда пригодился бы такой полезный метод, как этот:

 private static Boolean isBitSet(byte b, int bit)
{
    return (b amp; (1 << bit)) != 0;
}
 

(где bit колеблется от 0 до 7). Каждый раз next() , когда вызывался, вам нужно было бы увеличивать свой битовый индекс в пределах текущего байта и увеличивать байтовый индекс в массиве байтов, если вы достигли «9-го бита».

Это не так уж трудно, но немного больно. Дайте мне знать, если вам нужен пример реализации…

Ответ №2:

 public class ByteArrayBitIterable implements Iterable<Boolean> {
    private final byte[] array;

    public ByteArrayBitIterable(byte[] array) {
        this.array = array;
    }

    public Iterator<Boolean> iterator() {
        return new Iterator<Boolean>() {
            private int bitIndex = 0;
            private int arrayIndex = 0;

            public boolean hasNext() {
                return (arrayIndex < array.length) amp;amp; (bitIndex < 8);
            }

            public Boolean next() {
                Boolean val = (array[arrayIndex] >> (7 - bitIndex) amp; 1) == 1;
                bitIndex  ;
                if (bitIndex == 8) {
                    bitIndex = 0;
                    arrayIndex  ;
                }
                return val;
            }

            public void remove() {
                throw new UnsupportedOperationException();
            }
        };
    }

    public static void main(String[] a) {
        ByteArrayBitIterable test = new ByteArrayBitIterable(
                   new byte[]{(byte)0xAA, (byte)0xAA});
        for (boolean b : test)
            System.out.println(b);
    }
}
 

Ответ №3:

Оригинал:

 for (int i = 0; i < byteArray.Length; i  )
{
   byte b = byteArray[i];
   byte mask = 0x01;
   for (int j = 0; j < 8; j  )
   {
      bool value = b amp; mask;
      mask << 1;
   }
}
 

Или используя идиомы Java

 for (byte b : byteArray ) {
  for ( int mask = 0x01; mask != 0x100; mask <<= 1 ) {
      boolean value = ( b amp; mask ) != 0;
  }
}
 

Комментарии:

1. Я бы сказал C#, если бы мне нужно было угадать.

2. @Оскар: Это оператор с левым сдвигом. В Java это тоже есть.

Ответ №4:

Альтернативой было бы использовать BitInputStream, подобный тому, который вы можете найти здесь, и написать такой код:

 BitInputStream bin = new BitInputStream(new ByteArrayInputStream(bytes));
    while(true){
        int bit = bin.readBit();
        // do something
    }
bin.close();
 

(Примечание: Код для краткости не содержит обработки исключений EOFException или IOException.)

Но я бы пошел с вариантом Джона Скитса и сделал это сам.

Ответ №5:

Мне нужно было немного потоковой передачи в моем приложении. Здесь вы можете найти мою реализацию BitArray. Это не настоящий шаблон итератора, но вы можете запросить 1-32 бита из массива потоковым способом. Позже в файле также есть альтернативная реализация под названием BitReader.

Ответ №6:

Я знаю, возможно, это не самый «крутой» способ сделать это, но вы можете извлечь каждый бит с помощью следующего кода.

     int n = 156;

String bin = Integer.toBinaryString(n);
System.out.println(bin);

char arr[] = bin.toCharArray();
for(int i = 0; i < arr.length;   i) {
    System.out.println("Bit number "   (i   1)   " = "   arr[i]);
}
 

10011100

Номер бита 1 = 1

Разрядное число 2 = 0

Разрядное число 3 = 0

Разрядное число 4 = 1

Разрядное число 5 = 1

Разрядное число 6 = 1

Разрядное число 7 = 0

Разрядное число 8 = 0

Комментарии:

1. Это круто, потому что в нем не используются эти «страшные» побитовые операции.

2. Я не вижу никакой необходимости использовать побитовый оператор для чего-то столь простого, как просил ОП: повторите перебор битов.

3. Это дало бы лучший ответ на вопрос, если бы показывало, как извлекать биты из массива байтов (вместо массива строк или символов)

Ответ №7:

Вы можете перебирать массив байтов и для каждого байта использовать побитовые операторы для перебора его битов.

Ответ №8:

В качестве альтернативы вы можете использовать BitSet для этого:

 byte[] bytes=...;
BitSet bitSet=BitSet.valueOf(bytes);
for(int i=0;i<bitSet.length();i  ){
    boolean bit=bitSet.get(i);
    //use your bit
}