Java에서는 선행 0을 유지하면서 바이트 배열을 16진수 문자열로 변환하려면 어떻게 해야 합니까?
md5 해시를 만들기 위한 자바 코드의 예를 들어 작업하고 있습니다.한 부분은 바이트에서 16진수 문자열로 결과를 변환합니다.
byte messageDigest[] = algorithm.digest();
StringBuffer hexString = new StringBuffer();
for (int i=0;i<messageDigest.length;i++) {
hexString.append(Integer.toHexString(0xFF & messageDigest[i]));
}
단, toHexString은 선두의 0을 드롭하고 있기 때문에 동작하지 않습니다.그렇다면 바이트 배열에서 선행 0을 유지하는 16진수 문자열로 전환하는 가장 간단한 방법은 무엇일까요?
Hex.encode를 확인합니다.Apache Commons 코덱의 HexString.
import org.apache.commons.codec.binary.Hex;
String hex = Hex.encodeHexString(bytes);
아래 것을 사용하셔도 됩니다.선두 0바이트와 초기 마이너스 바이트로 테스트했습니다.
public static String toHex(byte[] bytes) {
BigInteger bi = new BigInteger(1, bytes);
return String.format("%0" + (bytes.length << 1) + "X", bi);
}
는, 「16」을 합니다."x"
스트링 스트링
은 몇 입니다.Integer.toHexString()
필요한 경우 각 바이트에 선행 0을 추가합니다.다음과 같이 합니다.
public static String toHexString(byte[] bytes) {
StringBuilder hexString = new StringBuilder();
for (int i = 0; i < bytes.length; i++) {
String hex = Integer.toHexString(0xFF & bytes[i]);
if (hex.length() == 1) {
hexString.append('0');
}
hexString.append(hex);
}
return hexString.toString();
}
이 메서드는 Java Architecture for XML Binding(JAXB)의 일부이며, 이 메서드를 사용하면, EXB 를 간단하게 변환할 수 있습니다.byte[]
16진수 스트링으로 변환합니다.이 클래스에는 다른 유용한 데이터 조작 방법도 다수 포함되어 있었다.
Java 8 이전 버전에서는 JAXB는 Java 표준 라이브러리의 일부였습니다.모든 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
스티브의 제출은 마음에 들었지만, 그는 몇 가지 변수 없이도 해낼 수 있었고, 그 과정에서 몇 줄의 줄을 저장할 수 있었습니다.
public static String toHexString(byte[] bytes) {
char[] hexArray = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
char[] hexChars = new char[bytes.length * 2];
int v;
for ( int j = 0; j < bytes.length; j++ ) {
v = bytes[j] & 0xFF;
hexChars[j*2] = hexArray[v/16];
hexChars[j*2 + 1] = hexArray[v%16];
}
return new String(hexChars);
}
이 기능이 마음에 드는 것은 BigInteger 블랙박스 변환에 의존하지 않고 정확히 무엇을 하고 있는지 알 수 있고, 선행 제로와 같은 코너 케이스에 대해 걱정할 필요가 없다는 점입니다.이 루틴은 4비트 니블마다 16진수 문자로 변환합니다.테이블 룩업을 사용하기 때문에 아마 빠를 겁니다.v/16 및 v%16을 비트 단위 이동 및 AND로 대체하면 더 빠를 수 있지만, 지금은 테스트하기가 너무 귀찮습니다.
Integer.toHexString이 조금 느리다는 것을 알았습니다.많은 바이트를 변환하는 경우 "00"을 포함하는 문자열 배열을 구축하는 것을 고려해 보십시오."FF"를 선택하고 정수를 인덱스로 사용합니다.예.
hexString.append(hexArray[0xFF & messageDigest[i]]);
이렇게 하면 더 빠르고 정확한 길이가 보장됩니다.문자열 배열만 있으면 됩니다.
String[] hexArray = {
"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"};
저도 같은 것을 찾고 있었습니다.여기서 좋은 아이디어를 찾고 있었습니다만, 몇 가지 마이크로 벤치마크를 실시했습니다.아래가 가장 빠른 것으로 나타났습니다(Ayman의 위 버전부터 약 2배 빠른 속도로 변경되었으며 Steve의 위 버전보다 약 50% 빠릅니다).
public static String hash(String text, String algorithm)
throws NoSuchAlgorithmException {
byte[] hash = MessageDigest.getInstance(algorithm).digest(text.getBytes());
return new BigInteger(1, hash).toString(16);
}
편집: 오류 - 기본적으로 kjiannakakis와 같기 때문에 선행 0이 제거될 수 있습니다.그러나, 이것을 다음과 같이 수정하는 것이 여전히 가장 빠릅니다.
public static String hash(String text, String algorithm)
throws NoSuchAlgorithmException {
byte[] hash = MessageDigest.getInstance(algorithm).digest(text.getBytes());
BigInteger bi = new BigInteger(1, hash);
String result = bi.toString(16);
if (result.length() % 2 != 0) {
return "0" + result;
}
return result;
}
static String toHex(byte[] digest) {
StringBuilder sb = new StringBuilder();
for (byte b : digest) {
sb.append(String.format("%1$02X", b));
}
return sb.toString();
}
고정 길이에는 다음과 같은 해시를 사용합니다.
md5sum = String.format("%032x", new BigInteger(1, md.digest()));
0
★★★★★★★★★★★★★★★★...
String result = String.format("%0" + messageDigest.length + "s", hexString.toString())
이미 가지고 계신 걸 감안하면 그게 가장 빠른 해결책입니다.할 수 는, 「」를 참조해 주세요.String.format
는 동시에 16진수 문자열로 변환할 수 있습니다.
Guava는 또한 매우 심플합니다.
BaseEncoding.base16().encode( bytes );
Apache Commons를 사용할 수 없을 때 좋은 대안입니다.또한 다음과 같은 출력 제어 기능도 갖추고 있습니다.
byte[] bytes = new byte[] { 0xa, 0xb, 0xc, 0xd, 0xe, 0xf };
BaseEncoding.base16().lowerCase().withSeparator( ":", 2 ).encode( bytes );
// "0a:0b:0c:0d:0e:0f"
이 솔루션은 약간 구식이므로 메모리 효율이 높을 것입니다.
public static String toHexString(byte bytes[]) {
if (bytes == null) {
return null;
}
StringBuffer sb = new StringBuffer();
for (int iter = 0; iter < bytes.length; iter++) {
byte high = (byte) ( (bytes[iter] & 0xf0) >> 4);
byte low = (byte) (bytes[iter] & 0x0f);
sb.append(nibble2char(high));
sb.append(nibble2char(low));
}
return sb.toString();
}
private static char nibble2char(byte b) {
byte nibble = (byte) (b & 0x0f);
if (nibble < 10) {
return (char) ('0' + nibble);
}
return (char) ('a' + nibble - 10);
}
다른 옵션
public static String toHexString(byte[]bytes) {
StringBuilder sb = new StringBuilder(bytes.length*2);
for(byte b: bytes)
sb.append(Integer.toHexString(b+0x800).substring(1));
return sb.toString();
}
선두 0을 유지하기 위해 Paul이 제안한 내용(예: md5 해시)에 대한 작은 변화를 다음에 나타냅니다.
public static String MD5hash(String text) throws NoSuchAlgorithmException {
byte[] hash = MessageDigest.getInstance("MD5").digest(text.getBytes());
return String.format("%032x",new BigInteger(1, hash));
}
아이먼이 제안한 것보다 더 형편없어 보여서 미안해
static String toHex(byte[] digest) {
String digits = "0123456789abcdef";
StringBuilder sb = new StringBuilder(digest.length * 2);
for (byte b : digest) {
int bi = b & 0xff;
sb.append(digits.charAt(bi >> 4));
sb.append(digits.charAt(bi & 0xf));
}
return sb.toString();
}
concat와 append 함수가 매우 느릴 수 있습니다.아래는 (이전 게시물보다) 훨씬 더 빨랐습니다.출력을 빌드할 때 char 배열로 변경하는 것이 출력을 고속화하는 주요 요인이었습니다.Hex.encode와 비교한 적이 없습니다.Brandon DuRette가 제안한 Hex.
public static String toHexString(byte[] bytes) {
char[] hexArray = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
char[] hexChars = new char[10000000];
int c = 0;
int v;
for ( j = 0; j < bytes.length; j++ ) {
v = bytes[j] & 0xFF;
hexChars[c] = hexArray[v/16];
c++;
hexChars[c] = hexArray[v%16];
c++;
}
return new String(hexChars, 0, c); }
MD5 해시에 사용하는 것은 다음과 같습니다.
public static String getMD5(String filename)
throws NoSuchAlgorithmException, IOException {
MessageDigest messageDigest =
java.security.MessageDigest.getInstance("MD5");
InputStream in = new FileInputStream(filename);
byte [] buffer = new byte[8192];
int len = in.read(buffer, 0, buffer.length);
while (len > 0) {
messageDigest.update(buffer, 0, len);
len = in.read(buffer, 0, buffer.length);
}
in.close();
return new BigInteger(1, messageDigest.digest()).toString(16);
}
EDIT: 테스트를 해봤는데, 이것과 함께 후행 0도 잘려나간다는 것을 알게 되었습니다.그러나 이것은 처음에만 발생할 수 있기 때문에 예상 길이와 패드를 적절히 비교할 수 있습니다.
외부 라이브러리를 사용하지 않고 쓰기 작업을 줄일 수 있습니다.
String hex = (new HexBinaryAdapter()).marshal(md5.digest(YOUR_STRING.getBytes()))
이 솔루션에는 비트 쉬프나 마스킹, 룩업 테이블 또는 외부 라이브러리가 필요하지 않으며, 가능한 한 짧은 시간이 필요합니다.
byte[] digest = new byte[16];
Formatter fmt = new Formatter();
for (byte b : digest) {
fmt.format("%02X", b);
}
fmt.toString()
byte messageDigest[] = algorithm.digest();
StringBuffer hexString = new StringBuffer();
for (int i = 0; i < messageDigest.length; i++) {
String hexByte = Integer.toHexString(0xFF & messageDigest[i]);
int numDigits = 2 - hexByte.length();
while (numDigits-- > 0) {
hexString.append('0');
}
hexString.append(hexByte);
}
IMHO는 선행 0을 제거하기 위한 스니펫을 제공하는 위의 모든 솔루션이 잘못되었습니다.
byte messageDigest[] = algorithm.digest();
for (int i = 0; i < messageDigest.length; i++) {
hexString.append(Integer.toHexString(0xFF & messageDigest[i]));
}
이 스니펫에 따르면 8비트가 바이트 배열에서 반복되어 정수로 변환되고(Integer.toHexString 함수가 int를 인수로 받아들이기 때문에), 그 정수가 대응하는 해시 값으로 변환됩니다.예를 들어 00000001 00000001 이 바이너리에 있는 경우 코드에 따르면 hexString 변수는 16진수 값으로 0x11 이며 올바른 값은 0x0101 이어야 합니다.따라서 MD5를 계산할 때 길이가 32바이트 미만인 해시(0이 누락되었기 때문에)를 얻을 수 있습니다.이 해시는 MD5 해시의 암호화 고유 속성을 충족하지 못할 수 있습니다.
이 문제의 해결책은 위의 코드 스니펫을 다음 스니펫으로 대체하는 것입니다.
byte messageDigest[] = algorithm.digest();
for (int i = 0; i < messageDigest.length; i++) {
int temp=0xFF & messageDigest[i];
String s=Integer.toHexString(temp);
if(temp<=0x0F){
s="0"+s;
}
hexString.append(s);
}
그러면 1바이트에 대해 2char 길이의 문자열이 생성됩니다.
public String toString(byte b){
final char[] Hex = new String("0123456789ABCDEF").toCharArray();
return "0x"+ Hex[(b & 0xF0) >> 4]+ Hex[(b & 0x0F)];
}
그리고 어떻게 다시 asciii에서 byte 배열로 변환할 수 있습니까?
나는 다음 코드를 따라 Jemenake가 준 ASCII로 변환했다.
public static String toHexString(byte[] bytes) {
char[] hexArray = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
char[] hexChars = new char[bytes.length * 2];
int v;
for ( int j = 0; j < bytes.length; j++ ) {
v = bytes[j] & 0xFF;
hexChars[j*2] = hexArray[v/16];
hexChars[j*2 + 1] = hexArray[v%16];
}
return new String(hexChars);
}
나의 변종
StringBuilder builder = new StringBuilder();
for (byte b : bytes)
{
builder.append(Character.forDigit(b/16, 16));
builder.append(Character.forDigit(b % 16, 16));
}
System.out.println(builder.toString());
나한테는 효과가 있어
그게 잘못된 해결책인가요?(자바 포함)
// Create MD5 Hash
MessageDigest digest = java.security.MessageDigest.getInstance("MD5");
digest.update(s.getBytes());
byte[] md5sum = digest.digest();
BigInteger bigInt = new BigInteger(1, md5sum);
String stringMD5 = bigInt.toString(16);
// Fill to 32 chars
stringMD5 = String.format("%32s", stringMD5).replace(' ', '0');
return stringMD5;
기본적으로 공간을 0으로 바꿉니다.
아무도 다음과 같은 해결책을 내놓지 않았다는 사실에 놀랐습니다.
StringWriter sw = new StringWriter();
com.sun.corba.se.impl.orbutil.HexOutputStream hex = new com.sun.corba.se.impl.orbutil.HexOutputStream(sw);
hex.write(byteArray);
System.out.println(sw.toString());
또는 다음과 같이 할 수 있습니다.
byte[] digest = algorithm.digest();
StringBuilder byteContet = new StringBuilder();
for(byte b: digest){
byteContent = String.format("%02x",b);
byteContent.append(byteContent);
}
짧고 단순하며 기본적으로 형식 변경에 불과합니다.
이 또한 동등하지만 Apache util HexBin을 사용하면 코드가 다음과 같이 감소합니다.
HexBin.encode(messageDigest).toLowerCase();
언급URL : https://stackoverflow.com/questions/332079/in-java-how-do-i-convert-a-byte-array-to-a-string-of-hex-digits-while-keeping-l
'programing' 카테고리의 다른 글
파일에 대해 DragEnd 이벤트가 발생하지 않음 (0) | 2022.06.27 |
---|---|
Bootstrap-vue 모달 3회 오픈 (0) | 2022.06.27 |
Vue.js를 사용한 계산 상태 및 변환 상태 문제 (0) | 2022.06.27 |
컴파일 시 -pthread 플래그의 중요성 (0) | 2022.06.27 |
시스템의 차이.exit(0), System.exit(-1), System.exit(1) (Java 의 경우) (0) | 2022.06.27 |