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=new Encoder(false);
static final Encoder UPPER=new Encoder(true);
}
public static Encoder getEncoder(){
return Encoder.LOWER;
}
public static Encoder getUpperEncoder(){
return Encoder.UPPER;
}
//...
}
298
我的解决方案是基于MaybeWeCouldStealAVan 's solution, but does not rely on any additionaly allocated lookup tables. It does not uses any ' int-to-char'演员黑客(实际上, Character.forDigit() 做了,执行一些比较以检查数字真正是什么),因此可能会慢一些 . 请随时随地使用它 . 干杯 .
public static String bytesToHex(final byte[] bytes)
{
final int numBytes = bytes.length;
final char[] container = new char[numBytes * 2];
for (int i = 0; i < numBytes; i++)
{
final int b = bytes[i] & 0xFF;
container[i * 2] = Character.forDigit(b >>> 4, 0x10);
container[i * 2 + 1] = Character.forDigit(b & 0xF, 0x10);
}
return new String(container);
}
22
public static byte[] hexStringToByteArray(String s) {
int len = s.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ Character.digit(s.charAt(i+1), 16));
}
return data;
}
40
我更喜欢用这个:
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);
}
import java.math.BigInteger;
import static java.lang.System.out;
public final class App2 {
// | proposed solution.
public static String encode(byte[] bytes) {
final int length = bytes.length;
// | BigInteger constructor throws if it is given an empty array.
if (length == 0) {
return "00";
}
final int evenLength = (int)(2 * Math.ceil(length / 2.0));
final String format = "%0" + evenLength + "x";
final String result = String.format (format, new BigInteger(bytes));
return result;
}
public static void main(String[] args) throws Exception {
// 00
out.println(encode(new byte[] {}));
// 01
out.println(encode(new byte[] {1}));
//203040
out.println(encode(new byte[] {0x20, 0x30, 0x40}));
// 416c6c20796f75722062617365206172652062656c6f6e6720746f2075732e
out.println(encode("All your base are belong to us.".getBytes()));
}
}
public static String encode(byte[] bytes) {
final int length = bytes.length;
// | BigInteger constructor throws if it is given an empty array.
if (length == 0) {
return "00";
}
return new BigInteger(bytes).toString(16);
}
22 回答
这是一个类似
java.util.Base64
的实现(部分),不是很漂亮吗?我的解决方案是基于MaybeWeCouldStealAVan 's solution, but does not rely on any additionaly allocated lookup tables. It does not uses any ' int-to-char'演员黑客(实际上,
Character.forDigit()
做了,执行一些比较以检查数字真正是什么),因此可能会慢一些 . 请随时随地使用它 . 干杯 .我更喜欢用这个:
它可以稍微灵活地适应已接受的答案 . 就个人而言,我同时保留了接受的答案和这种重载,可以在更多情况下使用 .
最简单的解决方案,没有外部库,没有数字常量:
使用
DatatypeConverter.printHexBinary()
. 你可以在http://docs.oracle.com/javase/6/docs/api/javax/xml/bind/DatatypeConverter.html阅读它的文档例如:
将导致:
如您所见,这将检索表示带前导零的字节数组的十六进制字符串 .
这个答案基本上与问题In Java, how do I convert a byte array to a string of hex digits while keeping leading zeros?相同
@maybewecouldstealavan提出的解决方案的一个小变体,它允许您在输出十六进制字符串中可视地将N个字节捆绑在一起:
那是:
这个简单的oneliner适合我
String result = new BigInteger(1, inputBytes).toString(16);
编辑 - 使用它将删除前导零,但他们为我的用例工作 . 感谢@Voicu指出它
Apache Commons Codec库有一个Hex类来完成这类工作 .
好的,有很多方法可以做到这一点,但是如果你决定使用一个库,我会建议在你的项目中讨论是否在添加新库之前已经在已经是项目一部分的库中实现了某些东西只是这样做 . 例如,如果您还没有
也许你有......
Guava 解决方案,为了完整性:
现在
hex
是"48656c6c6f20776f726c64"
.在此页面上找不到任何解决方案
使用循环
使用javax.xml.bind.DatatypeConverter编译正常但经常在运行时抛出java.lang.NoClassDefFoundError .
这是一个没有上述缺陷的解决方案(没有承诺我没有其他缺陷)
我无法在62个操作码下得到这个,但是如果你的第一个字节小于0x10就可以没有0填充,那么下面的解决方案只使用23个操作码 . 真的展示了如何“轻松实现自己”的解决方案,如“如果字符串长度为零则填充零”可能会变得相当昂贵,如果本机实现尚不可用(或者在这种情况下,如果BigInteger有一个选项以前缀为零)的toString) .
使用DataTypeConverter类
javax.xml.bind.DataTypeConverter
String hexString = DatatypeConverter.printHexBinary(bytes[] raw);
这个怎么样?
从讨论here,特别是this回答,这是我目前使用的功能:
我自己的微小基准测试(一百万字节一千万次,256字节一千万次)显示它比任何其他替代方案快得多,大约是长阵列的一半时间 . 与我从中得到的答案相比,切换到按位运算 - 如讨论中所建议的那样 - 为长阵列削减了大约20%的时间 . (编辑:当我说它比替代品更快时,我的意思是讨论中提供的替代代码 . 性能等同于Commons Codec,它使用非常相似的代码 . )
以存储查找表的次要成本,这种实现简单且非常快 .
我会使用这样的东西来固定长度,比如哈希:
我在这里发现了三种不同的方式:http://www.rgagnon.com/javadetails/java-0596.html
正如他所指出的那样,最优雅的一个就是这个:
我通常使用以下方法进行debuf语句,但我不知道这是否是最好的方法
//移动字节更有效//你也可以使用这个
如果你正在寻找一个与python完全相同的字节数组,我已经将这个Java实现转换为python .