자바에서 바이트 배열을 16진수로 변환하는 방법?
나는 16진수로 채워진 바이트 배열을 가지고 있다. 인쇄할 수 없는 요소들이 많기 때문에 쉬운 방법은 꽤 무의미하다.내가 필요한 것은 다음과 같은 형태의 정확한 육각 코드다.3a5f771c
여기서 논의한 결과, 특히 이 답변에서 현재 사용하고 있는 기능은 다음과 같다.
private static final char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray();
public static String bytesToHex(byte[] bytes) {
char[] hexChars = new char[bytes.length * 2];
for (int j = 0; j < bytes.length; j++) {
int v = bytes[j] & 0xFF;
hexChars[j * 2] = HEX_ARRAY[v >>> 4];
hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F];
}
return new String(hexChars);
}
나 자신의 작은 벤치마크(천 번 100만 바이트, 1천만 번 256만 바이트)는 긴 배열에서 시간의 절반 정도인 다른 어떤 대안보다 훨씬 빠른 것으로 나타났다.내가 가져간 답과 비교해 볼 때--- 토론에서 제시된 바와 같이--비트와이즈 ops로 전환하면 긴 배열 시간을 약 20% 단축할 수 있다. (편집:내가 대안보다 빠르다고 할 때, 나는 토론에서 제시된 대체 코드를 의미한다.성능은 매우 유사한 코드를 사용하는 커먼스 코덱과 동등하다.)
Java 9 콤팩트 문자열 관련 2k20 버전:
private static final byte[] HEX_ARRAY = "0123456789ABCDEF".getBytes(StandardCharsets.US_ASCII);
public static String bytesToHex(byte[] bytes) {
byte[] hexChars = new byte[bytes.length * 2];
for (int j = 0; j < bytes.length; j++) {
int v = bytes[j] & 0xFF;
hexChars[j * 2] = HEX_ARRAY[v >>> 4];
hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F];
}
return new String(hexChars, StandardCharsets.UTF_8);
}
Apache Commons Codec 라이브러리에는 이러한 유형의 작업만 수행하는 Hex 클래스가 있다.
import org.apache.commons.codec.binary.Hex;
String foo = "I am a string";
byte[] bytes = foo.getBytes();
System.out.println( Hex.encodeHexString( bytes ) );
XML 바인딩을 위한 JAXB(Java Architecture for XML Binding)의 일부인 메소드는 변환을 위한 편리한 방법이었다.byte[]
육각의 끈으로이 세분류는 또한 많은 다른 유용한 데이터 조작 방법을 포함했다.
자바 8 및 이전 버전에서 JAXB는 자바 표준 라이브러리의 일부였다.모든 Java EE 패키지를 자체 라이브러리로 이동하기 위한 노력의 일환으로 Java 9에서 사용되지 않고 Java 11에서 제거되었다.이야기가 길다.지금javax.xml.bind
존재하지 않으며, 만약 당신이 JAXB를 사용하기를 원한다면, JAXB는 다음과 같다.DatatypeConverter
Maven에서 JAXB API와 JAXB Runtime을 설치해야 한다.
사용 예:
byte bytes[] = {(byte)0, (byte)0, (byte)134, (byte)0, (byte)61};
String hex = javax.xml.bind.DatatypeConverter.printHexBinary(bytes);
결과:
000086003D
이 답은 이것과 같다.
가장 간단한 솔루션, 외부 lib 없음, 숫자 상수 없음:
public static String byteArrayToHex(byte[] a) {
StringBuilder sb = new StringBuilder(a.length * 2);
for(byte b: a)
sb.append(String.format("%02x", b));
return sb.toString();
}
다음은 단순(원라이너)에서 복합(거대 라이브러리)으로 정렬된 몇 가지 일반적인 옵션이다.성능에 관심이 있는 경우 아래의 마이크로 벤치마크를 참조하십시오.
옵션 1: 코드 조각 - 단순(JDK/Android만 사용)
옵션 1a: BigInteger
아주 하는 이다.BigInteger
의 16진법:
new BigInteger(1, someByteArray).toString(16);
임의 바이트 문자열이 아닌 숫자를 처리하므로 선행 0은 생략된다는 점에 유의하십시오(예: 원하는 것이 될 수도 있고 아닐 수도 있음).000AE3
대0AE3
3바이트 입력용).이 또한 옵션 2에 비해 약 100배 느릴 정도로 매우 느리다.
옵션 1b: 문자열.형식 지정
%X
자리 표시자, 대부분의 원시 유형을 인코딩할 수 있음(short
int
long
)에서 16진수까지:
String.format("%X", ByteBuffer.wrap(eightByteArray).getLong());
옵션 1c: 정수/길이(4/8바이트 어레이만)
4바이트 배열을 독점적으로 사용하는 경우 정수 클래스의 메소드를 사용할 수 있다.
Integer.toHexString(ByteBuffer.wrap(fourByteArray).getInt());
8바이트 배열에서도 같은 기능을 하며,
Long.toHexString(ByteBuffer.wrap(eightByteArray).getLong());
옵션 2: 코드 조각 - 고급
여기 상/하/하/하/내장을 지원하는 복사 및 붙여넣기 가능한 코드 조각이 있다.메모리 복잡성을 최소화하고 성능을 극대화하도록 최적화되었으며, 모든 최신 자바 버전(5+)과 호환되어야 한다.
private static final char[] LOOKUP_TABLE_LOWER = new char[]{0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66};
private static final char[] LOOKUP_TABLE_UPPER = new char[]{0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46};
public static String encode(byte[] byteArray, boolean upperCase, ByteOrder byteOrder) {
// our output size will be exactly 2x byte-array length
final char[] buffer = new char[byteArray.length * 2];
// choose lower or uppercase lookup table
final char[] lookup = upperCase ? LOOKUP_TABLE_UPPER : LOOKUP_TABLE_LOWER;
int index;
for (int i = 0; i < byteArray.length; i++) {
// for little endian we count from last to first
index = (byteOrder == ByteOrder.BIG_ENDIAN) ? i : byteArray.length - i - 1;
// extract the upper 4 bit and look up char (0-A)
buffer[i << 1] = lookup[(byteArray[index] >> 4) & 0xF];
// extract the lower 4 bit and look up char (0-A)
buffer[(i << 1) + 1] = lookup[(byteArray[index] & 0xF)];
}
return new String(buffer);
}
public static String encode(byte[] byteArray) {
return encode(byteArray, false, ByteOrder.BIG_ENDIAN);
}
Apache v2 라이센스와 디코더가 포함된 전체 소스 코드는 여기에서 찾을 수 있다.
옵션 3: 최적화된 작은 라이브러리 사용: 바이트-자바
이전 프로젝트를 작업하는 동안, 나는 자바에서 바이트로 작업하기 위해 이 작은 도구 키트를 만들었다.외부 의존성이 없고 자바 7+와 호환된다.여기에는 매우 빠르고 잘 테스트된 HEX en/decoder가 포함된다.
import at.favre.lib.bytes.Bytes;
...
Bytes.wrap(someByteArray).encodeHex()
당신은 그것을 Github: bytes-java에서 확인할 수 있다.
옵션 4: Apache Commons 코덱
물론 좋은 '올 커먼즈 코덱'도 있다.(앞서 경고의견)위에서 설명한 프로젝트를 진행하는 동안 나는 코드를 분석했고 상당히 실망했다; 많은 중복된 미조직 코드, 구식 코덱과 이국적인 코덱들은 아마도 인기 코덱의 매우 극소수 및 상당히 과잉 엔지니어링되고 느린 구현에 유용할 것이다. 그러므로 만약 당신이 그것을 사용하기를 원하거나 대안을 원한다면 나는 정보에 입각한 결정을 내릴 것이다.어쨌든, 만약 여전히 그것을 사용하고 싶다면, 여기 코드 조각이 있다.
import org.apache.commons.codec.binary.Hex;
...
Hex.encodeHexString(someByteArray));
옵션 5: Google 과바
종종 당신은 이미 과바를 의존으로 가지고 있다.그렇다면 다음을 사용하십시오.
import com.google.common.io.BaseEncoding;
...
BaseEncoding.base16().lowerCase().encode(someByteArray);
옵션 6: 스프링 보안
Spring Security와 함께 Spring 프레임워크를 사용하는 경우 다음을 사용할 수 있다.
import org.springframework.security.crypto.codec.Hex
...
new String(Hex.encode(someByteArray));
옵션 7: 번시 성
이미 보안 프레임워크인 Bouncy Castle을 사용하고 있다면 Bouncy Castle을 사용할 수 있다.Hex
활용:
import org.bouncycastle.util.encoders.Hex;
...
Hex.toHexString(someByteArray);
그렇지 않은 옵션 8: Java 9+ 호환성 또는 'JAXBs javax/xml/bind/DatatypeConverter 사용 안 함'
이전 Java(8 이하) 버전에서는 JAXB에 대한 Java 코드가 런타임 종속성으로 포함되었다.Java 9와 Jigsaw 모듈화 이후 당신의 코드는 명시적인 선언 없이는 그것의 모듈 외부의 다른 코드에 접근할 수 없다.따라서 다음과 같은 예외가 발생할 경우 주의하십시오.
java.lang.NoClassDefFoundError: javax/xml/bind/JAXBException
Java 9+를 사용하여 JVM에서 실행되는 경우.그렇다면 위의 대안 중 하나로 구현을 전환하십시오.이 질문을 참조하십시오.
마이크로 벤치마크
간단한 JMH 마이크로 벤치마크 인코딩 바이트 배열의 크기가 서로 다른 결과를 나타낸다.이 값은 초당 연산이기 때문에 더 높은 값이 좋다.마이크로 벤치마크는 실제 세계의 행동을 나타내지 않는 경우가 매우 많으므로 이 결과를 대수롭지 않게 여긴다.
| Name (ops/s) | 16 byte | 32 byte | 128 byte | 0.95 MB |
|----------------------|-----------:|-----------:|----------:|--------:|
| Opt1: BigInteger | 2,088,514 | 1,008,357 | 133,665 | 4 |
| Opt2/3: Bytes Lib | 20,423,170 | 16,049,841 | 6,685,522 | 825 |
| Opt4: Apache Commons | 17,503,857 | 12,382,018 | 4,319,898 | 529 |
| Opt5: Guava | 10,177,925 | 6,937,833 | 2,094,658 | 257 |
| Opt6: Spring | 18,704,986 | 13,643,374 | 4,904,805 | 601 |
| Opt7: BC | 7,501,666 | 3,674,422 | 1,077,236 | 152 |
| Opt8: JAX-B | 13,497,736 | 8,312,834 | 2,590,940 | 346 |
사양: JDK 8u202, i7-7700K, Win10, 24GB Ram.여기서 전체 벤치마크를 참조하십시오.
완전성을 위한 Guava 솔루션:
import com.google.common.io.BaseEncoding;
...
byte[] bytes = "Hello world".getBytes(StandardCharsets.UTF_8);
final String hex = BaseEncoding.base16().lowerCase().encode(bytes);
지금hex
이다"48656c6c6f20776f726c64"
.
이 간단한 온엘리너는 나에게 효과가 있다.
String result = new BigInteger(1, inputBytes).toString(16);
편집 - 이 옵션을 사용하면 선행 0이 제거되지만, Hey는 내 사용 사례에서 작동했다. @Voicu.
이런 걸 해시 같은 고정된 길이로 쓸 거야
md5sum = String.format("%032x", new BigInteger(1, md.digest()));
클래스 사용DataTypeConverterjavax.xml.bind.DataTypeConverter
String hexString = DatatypeConverter.printHexBinary(bytes[] raw);
나는 여기서 세 가지 다른 방법을 찾았다: 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();
}
조회표를 저장하는 데 드는 사소한 비용으로 이 구현은 간단하고 매우 빠르다.
private static final char[] BYTE2HEX=(
"000102030405060708090A0B0C0D0E0F"+
"101112131415161718191A1B1C1D1E1F"+
"202122232425262728292A2B2C2D2E2F"+
"303132333435363738393A3B3C3D3E3F"+
"404142434445464748494A4B4C4D4E4F"+
"505152535455565758595A5B5C5D5E5F"+
"606162636465666768696A6B6C6D6E6F"+
"707172737475767778797A7B7C7D7E7F"+
"808182838485868788898A8B8C8D8E8F"+
"909192939495969798999A9B9C9D9E9F"+
"A0A1A2A3A4A5A6A7A8A9AAABACADAEAF"+
"B0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF"+
"C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF"+
"D0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF"+
"E0E1E2E3E4E5E6E7E8E9EAEBECEDEEEF"+
"F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF").toCharArray();
;
public static String getHexString(byte[] bytes) {
final int len=bytes.length;
final char[] chars=new char[len<<1];
int hexIndex;
int idx=0;
int ofs=0;
while (ofs<len) {
hexIndex=(bytes[ofs++] & 0xFF)<<1;
chars[idx++]=BYTE2HEX[hexIndex++];
chars[idx++]=BYTE2HEX[hexIndex];
}
return new String(chars);
}
외부 라이브러리를 사용하거나 루프와 상수를 기반으로 코드를 작성할 필요가 없다.
이것만으로도 충분하다.
byte[] theValue = .....
String hexaString = new BigInteger(1, theValue).toString(16);
Java 17에는 HexFormat 클래스가 포함되어 있으므로 다음을 간단히 수행할 수 있다.
HexFormat.of().formatHex(bytes);
소문자/상소문자, 구분자, 접두사, 접미사 등으로 구성을 지원한다.
이건 어때?
String byteToHex(final byte[] hash)
{
Formatter formatter = new Formatter();
for (byte b : hash)
{
formatter.format("%02x", b);
}
String result = formatter.toString();
formatter.close();
return result;
}
헥스포맷은 Java 17에서 추가됨:
String hex = HexFormat.of().formatHex(array);
간단한 기능을 위해 유틸리티 병을 추가하는 것은 좋은 방법이 아니다.대신 자신의 유틸리티 클래스를 조립하십시오.다음은 더 빠른 구현이 가능하다.
public class ByteHex {
public static int hexToByte(char ch) {
if ('0' <= ch && ch <= '9') return ch - '0';
if ('A' <= ch && ch <= 'F') return ch - 'A' + 10;
if ('a' <= ch && ch <= 'f') return ch - 'a' + 10;
return -1;
}
private static final String[] byteToHexTable = new String[]
{
"00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "0A", "0B", "0C", "0D", "0E", "0F",
"10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "1A", "1B", "1C", "1D", "1E", "1F",
"20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "2A", "2B", "2C", "2D", "2E", "2F",
"30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "3A", "3B", "3C", "3D", "3E", "3F",
"40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "4A", "4B", "4C", "4D", "4E", "4F",
"50", "51", "52", "53", "54", "55", "56", "57", "58", "59", "5A", "5B", "5C", "5D", "5E", "5F",
"60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "6A", "6B", "6C", "6D", "6E", "6F",
"70", "71", "72", "73", "74", "75", "76", "77", "78", "79", "7A", "7B", "7C", "7D", "7E", "7F",
"80", "81", "82", "83", "84", "85", "86", "87", "88", "89", "8A", "8B", "8C", "8D", "8E", "8F",
"90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "9A", "9B", "9C", "9D", "9E", "9F",
"A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7", "A8", "A9", "AA", "AB", "AC", "AD", "AE", "AF",
"B0", "B1", "B2", "B3", "B4", "B5", "B6", "B7", "B8", "B9", "BA", "BB", "BC", "BD", "BE", "BF",
"C0", "C1", "C2", "C3", "C4", "C5", "C6", "C7", "C8", "C9", "CA", "CB", "CC", "CD", "CE", "CF",
"D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7", "D8", "D9", "DA", "DB", "DC", "DD", "DE", "DF",
"E0", "E1", "E2", "E3", "E4", "E5", "E6", "E7", "E8", "E9", "EA", "EB", "EC", "ED", "EE", "EF",
"F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "FA", "FB", "FC", "FD", "FE", "FF"
};
private static final String[] byteToHexTableLowerCase = new String[]
{
"00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "0a", "0b", "0c", "0d", "0e", "0f",
"10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "1a", "1b", "1c", "1d", "1e", "1f",
"20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "2a", "2b", "2c", "2d", "2e", "2f",
"30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "3a", "3b", "3c", "3d", "3e", "3f",
"40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "4a", "4b", "4c", "4d", "4e", "4f",
"50", "51", "52", "53", "54", "55", "56", "57", "58", "59", "5a", "5b", "5c", "5d", "5e", "5f",
"60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "6a", "6b", "6c", "6d", "6e", "6f",
"70", "71", "72", "73", "74", "75", "76", "77", "78", "79", "7a", "7b", "7c", "7d", "7e", "7f",
"80", "81", "82", "83", "84", "85", "86", "87", "88", "89", "8a", "8b", "8c", "8d", "8e", "8f",
"90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "9a", "9b", "9c", "9d", "9e", "9f",
"a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7", "a8", "a9", "aa", "ab", "ac", "ad", "ae", "af",
"b0", "b1", "b2", "b3", "b4", "b5", "b6", "b7", "b8", "b9", "ba", "bb", "bc", "bd", "be", "bf",
"c0", "c1", "c2", "c3", "c4", "c5", "c6", "c7", "c8", "c9", "ca", "cb", "cc", "cd", "ce", "cf",
"d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "da", "db", "dc", "dd", "de", "df",
"e0", "e1", "e2", "e3", "e4", "e5", "e6", "e7", "e8", "e9", "ea", "eb", "ec", "ed", "ee", "ef",
"f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9", "fa", "fb", "fc", "fd", "fe", "ff"
};
public static String byteToHex(byte b){
return byteToHexTable[b & 0xFF];
}
public static String byteToHex(byte[] bytes){
if(bytes == null) return null;
StringBuilder sb = new StringBuilder(bytes.length*2);
for(byte b : bytes) sb.append(byteToHexTable[b & 0xFF]);
return sb.toString();
}
public static String byteToHex(short[] bytes){
StringBuilder sb = new StringBuilder(bytes.length*2);
for(short b : bytes) sb.append(byteToHexTable[((byte)b) & 0xFF]);
return sb.toString();
}
public static String byteToHexLowerCase(byte[] bytes){
StringBuilder sb = new StringBuilder(bytes.length*2);
for(byte b : bytes) sb.append(byteToHexTableLowerCase[b & 0xFF]);
return sb.toString();
}
public static byte[] hexToByte(String hexString) {
if(hexString == null) return null;
byte[] byteArray = new byte[hexString.length() / 2];
for (int i = 0; i < hexString.length(); i += 2) {
byteArray[i / 2] = (byte) (hexToByte(hexString.charAt(i)) * 16 + hexToByte(hexString.charAt(i+1)));
}
return byteArray;
}
public static byte hexPairToByte(char ch1, char ch2) {
return (byte) (hexToByte(ch1) * 16 + hexToByte(ch2));
}
}
스트림을 사용하는 다른 방법은 다음과 같다.
private static String toHexString(byte[] bytes) {
return IntStream.range(0, bytes.length)
.mapToObj(i -> String.format("%02X", bytes[i]))
.collect(Collectors.joining());
}
public static String toHexString(byte[] bytes) {
StringBuilder sb = new StringBuilder();
if (bytes != null)
for (byte b:bytes) {
final String hexString = Integer.toHexString(b & 0xff);
if(hexString.length()==1)
sb.append('0');
sb.append(hexString);//.append(' ');
}
return sb.toString();//.toUpperCase();
}
DatatypeConverter를 사용하려면:
public String toHexString(byte... bytes) {
return Optional.ofNullable(bytes)
.filter(bs->bs.length>0)
.map(DatatypeConverter::printHexBinary)
.map(str->IntStream.range(0, str.length())
.filter(i->(i%2)==0) // take every second index
.mapToObj(i->"0x" + str.substring(i, i+2))
.collect(Collectors.joining(" ")))
.orElse("");
}
Spring Security 프레임워크를 사용하는 경우 다음을 사용하십시오.
import org.springframework.security.crypto.codec.Hex
final String testString = "Test String";
final byte[] byteArray = testString.getBytes();
System.out.println(Hex.encode(byteArray));
나는 이것을 사용하는 것을 선호한다.
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);
}
그것은 수용된 대답을 약간 더 융통성 있게 각색한 것이다.개인적으로, 나는 수용된 답과 이 과부하 양쪽을 더 많은 맥락에서 사용할 수 있도록 유지한다.
나는 보통 다음과 같은 방법을 디버프 진술에 사용하지만, 그것이 최선의 방법인지 아닌지 모르겠다.
private static String digits = "0123456789abcdef";
public static String toHex(byte[] data){
StringBuffer buf = new StringBuffer();
for (int i = 0; i != data.length; i++)
{
int v = data[i] & 0xff;
buf.append(digits.charAt(v >> 4));
buf.append(digits.charAt(v & 0xf));
}
return buf.toString();
}
좋아, 이렇게 할 수 있는 많은 방법들이 있지만, 만약 당신이 도서관을 사용하기로 결정한다면, 나는 단지 이것을 하기 위해 새 도서관을 추가하기 전에 이미 당신의 프로젝트의 일부인 도서관에서 어떤 것이 구현되었는지 알아보기 위해 당신의 프로젝트를 살펴보는 것을 제안할 것이다.예를 들어, 아직 가지고 있지 않은 경우
org.cg.properties.properties.육각
아마도 당신은...
오르간.xerces.property.usil.usil.헥스빈
출력 16진 문자열에 N바이트를 시각적으로 함께 묶을 수 있는 @we couldstealavan에 의해 제안된 솔루션의 작은 변종:
final static char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray();
final static char BUNDLE_SEP = ' ';
public static String bytesToHexString(byte[] bytes, int bundleSize /*[bytes]*/]) {
char[] hexChars = new char[(bytes.length * 2) + (bytes.length / bundleSize)];
for (int j = 0, k = 1; j < bytes.length; j++, k++) {
int v = bytes[j] & 0xFF;
int start = (j * 2) + j/bundleSize;
hexChars[start] = HEX_ARRAY[v >>> 4];
hexChars[start + 1] = HEX_ARRAY[v & 0x0F];
if ((k % bundleSize) == 0) {
hexChars[start + 2] = BUNDLE_SEP;
}
}
return new String(hexChars).trim();
}
즉,
bytesToHexString("..DOOM..".toCharArray().getBytes(), 2);
2E2E 444F 4F4D 2E2E
bytesToHexString("..DOOM..".toCharArray().getBytes(), 4);
2E2E444F 4F4D2E2E
이 페이지에서 찾을 수 없는 해결 방법을 찾을 수 없음
- 루프 사용
- javax.xml.bind를 사용하십시오.데이터타입컨버터는 잘 컴파일하지만 종종 java.lang을 던진다.NoClassDefoundError in runtime.
위와 같은 결함이 없는 해결책이 있다.
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()));
}
}
62개의 opcode로 이것을 얻을 수는 없었지만, 첫 번째 바이트가 0x10보다 작을 경우에 0 패딩 없이 살 수 있다면, 다음 솔루션은 23개의 opcode만 사용한다."끈 길이가 홀수인 경우 0을 가진 패드"와 같은 "자기자신을 구현하기 쉬운" 솔루션이 기본 구현을 아직 사용할 수 없는 경우(또는 이 경우 BigInteger가 toString에 0을 접두사할 수 있는 옵션이 있는 경우)에 얼마나 많은 비용이 소요될 수 있는지를 실제로 보여준다.
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);
}
내 솔루션은 아마도 WeCouldSteal을 기반으로 한다.AVan의 솔루션. 그러나 추가로 할당된 조회 테이블에 의존하지 않는다.그것은 어떠한 '내부' 캐스트도 사용하지 않는다. (사실,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);
}
여기에 a가 있다.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;
}
}
최근에 나는 바이트 스트림을 Hex 형식으로 로그에 덤프하기 위해 Hex 컨버터를 구현해야 했다.처음에 나는 그것을 사용하였다.Hex.encodeHex
여기서 이미 논의된 사항이야
그러나 바이트 배열을 표시/읽기 가능한 방식으로 표현하려는 경우io.netty.buffer
라이브러리는 인쇄할 수 없는 문자를 제거하는 문자열뿐만 아니라 Hex를 인쇄하기 때문에 매우 유용할 수 있다.
요구조건은 뭐랄까,
0010 56 56 09 35 32 f0 b2 00 50 4c 45 41 53 45 20 52 VV.52...PLEASE R
0020 45 2d 45 4e 54 45 52 20 4c 41 53 54 20 54 52 41 E-ENTER LAST TRA
0030 4e 53 41 43 54 49 4f 4e 00 04 NSACTION..
동일한 작업을 보다 쉽게 수행할 수 있는 가장 짧은 방법io.netty.buffer
이다
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
void hexDump(byte[] buf) {
ByteBuf byteBuf = Unpooled.wrappedBuffer(buf);
log.trace("Bytes received (Hex)\n" + ByteBufUtil.prettyHexDump(byteBuf.slice()));
}
maven을 사용하는 경우, 아래의 종속성을 pom.xml에 포함시키십시오(네티 페이지에서 최신 버전을 확인하십시오).
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-buffer</artifactId>
<version>4.1.68.Final</version>
</dependency>
출력:
+-------------------------------------------------+
| 0 1 2 3 4 5 6 7 8 9 a b c d e f |
+--------+-------------------------------------------------+----------------+
|00000010| 40 40 b3 f3 80 f3 80 f3 80 f1 48 f1 41 f1 4e f1 |@@........H.A.N.|
|00000020| 47 f1 49 f1 4e f1 47 b5 f1 52 f1 4f f1 43 f1 4b |G.I.N.G..R.O.C.K|
|00000030| f3 80 f3 80 41 b4 40 40 f3 80 f3 80 40 f3 80 04 |....A.@@....@...|
+--------+-------------------------------------------------+----------------+
참고로, 답변에서 논의된 방법을 사용하는 장거리(가장 효율적이지 않을 수 있다.
public static String hexDump(byte[] buf) throws DecoderException
{
ByteBuffer byteBuf = ByteBuffer.wrap(buf);
char[] result = Hex.encodeHex(byteBuf);
String bin = new String(result).toUpperCase();
String str = new String(Hex.decodeHex(bin), StandardCharsets.UTF_8);
str = str.replaceAll("[^!-~]", ".");
StringBuilder out = new StringBuilder();
int bytes_per_line = 16;
for (int pos = 0; pos < str.length(); pos += bytes_per_line) {
out.append(String.format("%04X ", pos));
if (2 * (pos + bytes_per_line) >= bin.length()) {
out.append(String.format("%-" + 2 * bytes_per_line + "s", bin.substring(2 * pos)).replaceAll("..", "$0 "));
} else {
out.append(bin.substring(2 * pos, 2 * (pos + bytes_per_line)).replaceAll("..", "$0 "));
}
out.append(" ");
if (pos + bytes_per_line > str.length()) {
out.append(str.substring(pos));
} else {
out.append(str.substring(pos, pos + bytes_per_line));
}
out.append("\n");
}
return out.toString();
}
만약 당신이 파이톤을 위해 정확히 이와 같은 바이트 배열을 찾고 있다면, 나는 이 자바 구현을 파이톤으로 변환했다.
class ByteArray:
@classmethod
def char(cls, args=[]):
cls.hexArray = "0123456789ABCDEF".encode('utf-16')
j = 0
length = (cls.hexArray)
if j < length:
v = j & 0xFF
hexChars = [None, None]
hexChars[j * 2] = str( cls.hexArray) + str(v)
hexChars[j * 2 + 1] = str(cls.hexArray) + str(v) + str(0x0F)
# Use if you want...
#hexChars.pop()
return str(hexChars)
array = ByteArray()
print array.char(args=[])
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;
}
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();
}
참조URL: https://stackoverflow.com/questions/9655181/how-to-convert-a-byte-array-to-a-hex-string-in-java
'IT이야기' 카테고리의 다른 글
일반 반환 유형 상한 - 인터페이스 대 클래스 - 놀랍도록 유효한 코드 (0) | 2022.05.27 |
---|---|
Vue + Vuetify에서 스낵바를 글로벌 구성 요소로 사용 (0) | 2022.05.27 |
index.html이 Javascript를 로드하지 않을 경우 Vue 앱을 실행하는 방법은? (0) | 2022.05.26 |
Intel C++ 컴파일러에서 NaN - NaN == 0.0인 이유 (0) | 2022.05.26 |
구성요소 렌더 함수에 무한 업데이트 루프가 있을 수 있음 (0) | 2022.05.26 |