Сохранить двоичную последовательность в байтовом массиве? - PullRequest
2 голосов
/ 23 марта 2011

Мне нужно сохранить пару двоичных последовательностей длиной 16 бит в байтовом массиве (длиной 2).Одно или два двоичных числа не меняются, поэтому функция, выполняющая преобразование, может оказаться излишней.Скажем, например, 16-битная двоичная последовательность - 1111000011110001. Как сохранить это в байтовом массиве длины два?

Ответы [ 2 ]

10 голосов
/ 23 марта 2011
    String val = "1111000011110001";
    byte[] bval = new BigInteger(val, 2).toByteArray();

Существуют и другие варианты, но я решил, что лучше использовать класс BigInteger, который имеет преобразование в байтовый массив, для такого рода проблем.Я предпочитаю, если, поскольку я могу создать экземпляр класса из String, который может представлять различные базы, такие как 8, 16 и т. Д., А также выводить его как таковой.

Редактировать: понедельники ...: P

public static byte[] getRoger(String val) throws NumberFormatException,
        NullPointerException {
    byte[] result = new byte[2];
    byte[] holder = new BigInteger(val, 2).toByteArray();

    if (holder.length == 1) result[0] = holder[0];
    else if (holder.length > 1) {
        result[1] = holder[holder.length - 2];
        result[0] = holder[holder.length - 1];
    }
    return result;
}

Пример:

int bitarray = 12321;
String val = Integer.toString(bitarray, 2);
System.out.println(new StringBuilder().append(bitarray).append(':').append(val)
  .append(':').append(Arrays.toString(getRoger(val))).append('\n'));
6 голосов
/ 15 августа 2013

Я был разочарован всеми решениями, которые я нашел для преобразования строк битов в байтовые массивы и наоборот - все они были ошибочными (даже решение BigInteger выше), и очень немногие из них настолько эффективны, насколько это должно быть.

Я понимаю, что OP имел дело только с битовой строкой в ​​массиве из двух байтов, для которой подход BitInteger, кажется, хорошо работает.Однако, поскольку этот пост является первым результатом поиска при поиске «битовой строки в байтовом массиве java» в Google, я опубликую свое общее решение для людей, имеющих дело с огромными строками и / или огромными байтовыми массивами.

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

Код

/**
 * Zips (compresses) bit strings to byte arrays and unzips (decompresses)
 * byte arrays to bit strings.
 *
 * @author ryan
 *
 */
public class BitZip {

  private static final byte[] BIT_MASKS = new byte[] {1, 2, 4, 8, 16, 32, 64, -128};
  private static final int BITS_PER_BYTE = 8;
  private static final int MAX_BIT_INDEX_IN_BYTE = BITS_PER_BYTE - 1;

  /**
   * Decompress the specified byte array to a string.
   * <p>
   * This function does not pad with zeros for any bit-string result
   * with a length indivisible by 8.
   *
   * @param bytes The bytes to convert into a string of bits, with byte[0]
   *              consisting of the least significant bits in the byte array.
   * @return The string of bits representing the byte array.
   */
  public static final String unzip(final byte[] bytes) {
    int byteCount = bytes.length;
    int bitCount = byteCount * BITS_PER_BYTE;

    char[] bits = new char[bitCount];
    {
      int bytesIndex = 0;
      int iLeft = Math.max(bitCount - BITS_PER_BYTE, 0);
      while (bytesIndex < byteCount) {
        byte value = bytes[bytesIndex];
        for (int b = MAX_BIT_INDEX_IN_BYTE; b >= 0; --b) {
          bits[iLeft + b] = ((value % 2) == 0 ? '0' : '1');
          value >>= 1;
        }
        iLeft = Math.max(iLeft - BITS_PER_BYTE, 0);
        ++bytesIndex;
      }
    }
    return new String(bits).replaceFirst("^0+(?!$)", "");
  }

  /**
   * Compresses the specified bit string to a byte array, ignoring trailing
   * zeros past the most significant set bit.
   *
   * @param bits The string of bits (composed strictly of '0' and '1' characters)
   *             to convert into an array of bytes.
   * @return The bits, as a byte array with byte[0] containing the least
   *         significant bits.
   */
  public static final byte[] zip(final String bits) {
    if ((bits == null) || bits.isEmpty()) {
      // No observations -- return nothing.
      return new byte[0];
    }
    char[] bitChars = bits.toCharArray();

    int bitCount = bitChars.length;
    int left;

    for (left = 0; left < bitCount; ++left) {
      // Ignore leading zeros.
      if (bitChars[left] == '1') {
        break;
      }
    }
    if (bitCount == left) {
      // Only '0's in the string.
      return new byte[] {0};
    }
    int cBits = bitCount - left;
    byte[] bytes = new byte[((cBits) / BITS_PER_BYTE) + (((cBits % BITS_PER_BYTE) > 0) ? 1 : 0)];
    {
      int iRight = bitCount - 1;
      int iLeft = Math.max(bitCount - BITS_PER_BYTE, left);
      int bytesIndex = 0;
      byte _byte = 0;

      while (bytesIndex < bytes.length) {
        while (iLeft <= iRight) {
          if (bitChars[iLeft] == '1') {
            _byte |= BIT_MASKS[iRight - iLeft];
          }
          ++iLeft;
        }
        bytes[bytesIndex++] = _byte;
        iRight = Math.max(iRight - BITS_PER_BYTE, left);
        iLeft = Math.max((1 + iRight) - BITS_PER_BYTE, left);
        _byte = 0;
      }
    }
    return bytes;
  }
}

Производительность

Мне было скучно на работе, поэтому я провел некоторое тестирование производительности, сравнивая с принятым здесь ответом для случая, когда N большое.(Делая вид, что игнорируем тот факт, что описанный выше подход BigInteger даже не работает должным образом в качестве общего подхода.)

Он работает со случайной битовой строкой размером 5М и случайным байтовым массивом размером 1М:

String -> byte[] -- BigInteger result: 39098ms
String -> byte[] -- BitZip result:     29ms
byte[] -> String -- Integer result:    138ms
byte[] -> String -- BitZip result:     71ms

И код:

  public static void main(String[] argv) {

    int testByteLength = 1000000;
    int testStringLength = 5000000;

    // Independently random.
    final byte[] randomBytes = new byte[testByteLength];
    final String randomBitString;
    {
      StringBuilder sb = new StringBuilder();
      Random rand = new Random();

      for (int i = 0; i < testStringLength; ++i) {
        int value = rand.nextInt(1 + i);
        sb.append((value % 2) == 0 ? '0' : '1');
        randomBytes[i % testByteLength] = (byte) value;
      }
      randomBitString = sb.toString();
    }

    byte[] resultCompress;
    String resultDecompress;
    {
      Stopwatch s = new Stopwatch();
      TimeUnit ms = TimeUnit.MILLISECONDS;
      {
        s.start();
        {
          resultCompress = compressFromBigIntegerToByteArray(randomBitString);
        }
        s.stop();
        {
          System.out.println("String -> byte[] -- BigInteger result: " + s.elapsed(ms) + "ms");
        }
        s.reset();
      }
      {
        s.start();
        {
          resultCompress = zip(randomBitString);
        }
        s.stop();
        {
          System.out.println("String -> byte[] -- BitZip result:     " + s.elapsed(ms) + "ms");
        }
        s.reset();
      }
      {
        s.start();
        {
          resultDecompress = decompressFromIntegerParseInt(randomBytes);
        }
        s.stop();
        {
          System.out.println("byte[] -> String -- Integer result:    " + s.elapsed(ms) + "ms");
        }
        s.reset();
      }
      {
        s.start();
        {
          resultDecompress = unzip(randomBytes);
        }
        s.stop();
        {
          System.out.println("byte[] -> String -- BitZip result:     " + s.elapsed(ms) + "ms");
        }
        s.reset();
      }
    }
  }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...