java 将二进制序列存储在字节数组中?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5409998/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 10:59:51  来源:igfitidea点击:

Store binary sequence in byte array?

javabinary

提问by Roger

I need to store a couple binary sequences that are 16 bits in length into a byte array (of length 2). The one or two binary numbers don't change, so a function that does conversion might be overkill. Say for example the 16 bit binary sequence is 1111000011110001. How do I store that in a byte array of length two?

我需要将几个长度为 16 位的二进制序列存储到一个字节数组(长度为 2)中。一两个二进制数不会改变,因此进行转换的函数可能有点过头了。比如说 16 位二进制序列是 1111000011110001。如何将它存储在长度为 2 的字节数组中?

回答by Margus

    String val = "1111000011110001";
    byte[] bval = new BigInteger(val, 2).toByteArray();

There are other options, but I found it best to use BigIntegerclass, that has conversion to byte array, for this kind of problems. I prefer if, because I can instantiate class from String, that can represent various bases like 8, 16, etc. and also output it as such.

还有其他选项,但我发现最好使用BigInteger具有转换为字节数组的类来解决此类问题。我更喜欢 if,因为我可以从 实例化类String,它可以表示各种基数,如 8、16 等,也可以这样输出。

Edit: Mondays ... :P

编辑:星期一...: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;
}

Example:

例子:

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'));

回答by Ryan

I have been disappointed with all of the solutions I have found to converting strings of bits to byte arrays and vice versa -- all have been buggy (even the BigInteger solution above), and very few are as efficient as they should be.

我对我发现的所有将位字符串转换为字节数组(反之亦然)的解决方案感到失望——所有解决方案都有问题(即使是上面的 BigInteger 解决方案),而且很少能达到应有的效率。

I realize the OP was only concerned with a bit string to an array of two bytes, which the BitInteger approach seems to work fine for. However, since this post is currently the first search result when searching "bit string to byte array java" in Google, I am going to post my general solution here for people dealing with huge strings and/or huge byte arrays.

我意识到 OP 只关心一个位串到一个由两个字节组成的数组,BitInteger 方法似乎可以正常工作。但是,由于这篇文章目前是在 Google 中搜索“位字符串到字节数组 java”时的第一个搜索结果,因此我将在这里发布我的通用解决方案,供处理大字符串和/或大字节数组的人使用。

Note that my solution below is the only solution I have ran that passes all of my test cases -- many online solutions to this relatively simple problem simply do not work.

请注意,我下面的解决方案是我运行的唯一通过所有测试用例的解决方案——许多针对这个相对简单问题的在线解决方案根本不起作用。

Code

代码

/**
 * 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;
  }
}

Performance

表现

I was bored at work so I did some performance testing comparing against the accepted answer here for when N is large. (Pretending to ignore the fact that the BigInteger approach posted above doesn't even work properly as a general approach.)

我在工作中感到无聊,所以当 N 很大时,我做了一些性能测试,与这里接受的答案进行比较。(假装忽略上面发布的 BigInteger 方法甚至不能作为一般方法正常工作的事实。)

This is running with a random bit string of size 5M and a random byte array of size 1M:

这是使用大小为 5M 的随机位串和大小为 1M 的随机字节数组运行的:

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

And the code:

和代码:

  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();
      }
    }
  }