我有一个字节数组充满十六进制数字和打印它的简单方式是相当没有意义的,因为有许多不可打印的元素。我需要的是精确的十六进制形式:3a5f771c


当前回答

private static String bytesToHexString(byte[] bytes, int length) {
        if (bytes == null || length == 0) return null;

        StringBuilder ret = new StringBuilder(2*length);

        for (int i = 0 ; i < length ; i++) {
            int b;

            b = 0x0f & (bytes[i] >> 4);
            ret.append("0123456789abcdef".charAt(b));

            b = 0x0f & bytes[i];
            ret.append("0123456789abcdef".charAt(b));
        }

        return ret.toString();
    }

其他回答

Java 17最终包含HexFormat类,所以你可以简单地做:

HexFormat.of().formatHex(bytes);

它支持配置为小写/大写,分隔符,前缀,后缀等。

为了完整起见,一个番石榴解决方案:

import com.google.common.io.BaseEncoding;
...
byte[] bytes = "Hello world".getBytes(StandardCharsets.UTF_8);
final String hex = BaseEncoding.base16().lowerCase().encode(bytes);

现在十六进制是“48656c6c6f20776f726c64”。

我发现了三种不同的方法: http://www.rgagnon.com/javadetails/java-0596.html

他还提到,我认为最优雅的一个是:

static final String HEXES = "0123456789ABCDEF";
public static String getHex( byte [] raw ) {
    if ( raw == null ) {
        return null;
    }
    final StringBuilder hex = new StringBuilder( 2 * raw.length );
    for ( final byte b : raw ) {
        hex.append(HEXES.charAt((b & 0xF0) >> 4))
            .append(HEXES.charAt((b & 0x0F)));
    }
    return hex.toString();
}

我更喜欢用这个:

final protected static char[] hexArray = "0123456789ABCDEF".toCharArray();
public static String bytesToHex(byte[] bytes, int offset, int count) {
    char[] hexChars = new char[count * 2];
    for ( int j = 0; j < count; j++ ) {
        int v = bytes[j+offset] & 0xFF;
        hexChars[j * 2] = hexArray[v >>> 4];
        hexChars[j * 2 + 1] = hexArray[v & 0x0F];
    }
    return new String(hexChars);
}

它是对公认答案的稍微灵活的改编。 就我个人而言,我既保留了公认的答案,也保留了这个重载,以便在更多的环境中使用。

这是一个java.util。类似base64的实现,是不是很漂亮?

import java.util.Arrays;

public class Base16/* a.k.a. Hex */ {
    public static class Encoder{
        private static char[] toLowerHex={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
        private static char[] toUpperHex={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
        private boolean upper;
        public Encoder(boolean upper) {
            this.upper=upper;
        }
        public String encode(byte[] data){
            char[] value=new char[data.length*2];
            char[] toHex=upper?toUpperHex:toLowerHex;
            for(int i=0,j=0; i<data.length; i++){
                int octet=data[i]&0xFF;
                value[j++]=toHex[octet>>4];
                value[j++]=toHex[octet&0xF];
            }
            return new String(value);
        }
        static final Encoder LOWER_CASE=new Encoder(false);
        static final Encoder UPPER_CASE=new Encoder(true);
    }
    public static Encoder getEncoder(){
        return Encoder.LOWER_CASE;
    }
    public static Encoder getUpperEncoder(){
        return Encoder.UPPER_CASE;
    }

    public static class Decoder{
      private static int maxIndex=102;
      private static int[] toIndex;
      static {
        toIndex=new int[maxIndex+1];
        Arrays.fill(toIndex, -1);
        char[] chars={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','a','b','c','d','e','f'};
        for(int i=0; i<chars.length; i++) {
          toIndex[(int)chars[i]]=i;
        }
      }
      public Decoder() {
      }
      public byte[] decode(String str) {
          char[] value=str.toCharArray();
          int start=0;
          if(value.length>2 && value[0]=='0' && (value[1]=='x' || value[1]=='X')) {
            start=2;
          }
          int byteLength=(value.length-start)/2; // ignore trailing odd char if exists
          byte[] data=new byte[byteLength];
          for(int i=start,j=0;i<value.length;i+=2,j++){
              int i1;
              int i2;
              char c1=value[i];
              char c2=value[i+1];
              if(c1>maxIndex || (i1=toIndex[(int)c1])<0 || c2>maxIndex || (i2=toIndex[(int)c2])<0) {
                throw new IllegalArgumentException("Invalid character at "+i);
              }
              data[j]=(byte)((i1<<4)+i2);
          }
          return data;
      }
      static final Decoder IGNORE_CASE=new Decoder();
  }
  public static Decoder getDecoder(){
      return Decoder.IGNORE_CASE;
  }
}