Java를 사용하여 16진수 덤프의 문자열 표현을 바이트 배열로 변환하시겠습니까?
16진수 값을 나타내는 긴 문자열(덤프에서)을 바이트 배열로 변환하는 방법을 찾고 있습니다.
여기에 같은 질문을 올린 사람만큼 잘 표현할 수는 없었을 것이다.
독창성을 방식대로 한다: 나에게 문자열이 하자."00A0BF" the the the the that로 하고 싶다.
byte[] {0x00,0xA0,0xBf}
어떻게 해야 하나?
는 자바 ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★BigInteger16살 0살하지만 나는 그것이 추하다고 생각하고 나는 간단한 것을 놓치고 있다고 확신한다.
업데이트(2021년) - Java 17에는 다음이 포함됩니다(25년 밖에 걸리지 않았습니다).
HexFormat.of().parseHex(s)
For older versions of Java:
다음은 지금까지 게시된 솔루션 중 가장 좋다고 생각하는 솔루션입니다.
/* s must be an even-length string. */
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;
}
개선되는 이유:
선행 0(BigInteger와 다름) 및 음의 바이트 값(Byte.parseByte와 다름)으로 안전합니다.
트트 a .
char[]스트링 빌더 스트링 빌더 스트링 빌더 스트링 빌더 스트링.사용할 수 없는 라이브러리 종속성 없음
.assert또는 인수가 안전하지 않은 경우 예외입니다.
한 줄:
import javax.xml.bind.DatatypeConverter;
public static String toHexString(byte[] array) {
return DatatypeConverter.printHexBinary(array);
}
public static byte[] toByteArray(String s) {
return DatatypeConverter.parseHexBinary(s);
}
경고:
- 9은 (se java.se.ee 를 한이(@Java 9 Jigsaw java.sejava.se の - @ @ @기기기기기기기기기기기기기기기기addaddaddaddaddadd so soaddaddaddadd so so soaddadd so so so so so so soaddaddaddaddadd so so so so so so so so so so so so so so so so so so so so so so so so so so so so so so so so so so so so -- -- -- --
eckes) - Android에서는 사용할 수 없습니다(덕분에).
Fabian이 점에 주의해 주세요). 단, 시스템에 문제가 있는 경우 소스코드를 사용할 수 있습니다.javax.xml웬일인지 그래.@님 덕분입니다.Bert Regelink소스 추출을 위해.
commons-codec의 Hex 클래스가 이를 대신합니다.
http://commons.apache.org/codec/
import org.apache.commons.codec.binary.Hex;
...
byte[] decoded = Hex.decodeHex("00A0BF");
// 0x00 0xA0 0xBF
Base Encoding을 사용할 수 있게 되었습니다.guava네, 네, 네.
BaseEncoding.base16().decode(string);
되돌리려면
BaseEncoding.base16().encode(bytes);
사실 BigInteger의 솔루션은 매우 훌륭하다고 생각합니다.
new BigInteger("00A0BF", 16).toByteArray();
편집: 포스터에서 알 수 있듯이 선행 0에는 안전하지 않습니다.
한 줄:
import javax.xml.bind.DatatypeConverter; public static String toHexString(byte[] array) { return DatatypeConverter.printHexBinary(array); } public static byte[] toByteArray(String s) { return DatatypeConverter.parseHexBinary(s); }
frackalizeR의 One-liners 뒤에 있는 실제 코드에 관심이 있는 분들을 위해 (기본적으로) javax.xml.bind는 Android에서는 사용할 수 없기 때문에 com.sun.xml.internal.bind에서 온 것입니다.DatatypeConverterImpl.java:
public byte[] parseHexBinary(String s) {
final int len = s.length();
// "111" is not a valid hex encoding.
if( len%2 != 0 )
throw new IllegalArgumentException("hexBinary needs to be even-length: "+s);
byte[] out = new byte[len/2];
for( int i=0; i<len; i+=2 ) {
int h = hexToBin(s.charAt(i ));
int l = hexToBin(s.charAt(i+1));
if( h==-1 || l==-1 )
throw new IllegalArgumentException("contains illegal character for hexBinary: "+s);
out[i/2] = (byte)(h*16+l);
}
return out;
}
private static int hexToBin( 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 char[] hexCode = "0123456789ABCDEF".toCharArray();
public String printHexBinary(byte[] data) {
StringBuilder r = new StringBuilder(data.length*2);
for ( byte b : data) {
r.append(hexCode[(b >> 4) & 0xF]);
r.append(hexCode[(b & 0xF)]);
}
return r.toString();
}
HexBinaryAdapter, 「마법」의 「」을 하고, 「마법」을 해제하는 .String ★★★★★★★★★★★★★★★★★」byte[].
import javax.xml.bind.annotation.adapters.HexBinaryAdapter;
public byte[] hexToBytes(String hexString) {
HexBinaryAdapter adapter = new HexBinaryAdapter();
byte[] bytes = adapter.unmarshal(hexString);
return bytes;
}
그건 제가 입력한 예에 불과합니다...저는 사실 그대로 사용하고 있기 때문에 별도의 사용 방법을 만들 필요가 없습니다.
다음은 실제 효과가 있는 방법입니다(기존의 몇 가지 반정답에 근거하고 있습니다.
private static byte[] fromHexString(final String encoded) {
if ((encoded.length() % 2) != 0)
throw new IllegalArgumentException("Input string must contain an even number of characters");
final byte result[] = new byte[encoded.length()/2];
final char enc[] = encoded.toCharArray();
for (int i = 0; i < enc.length; i += 2) {
StringBuilder curr = new StringBuilder(2);
curr.append(enc[i]).append(enc[i + 1]);
result[i/2] = (byte) Integer.parseInt(curr.toString(), 16);
}
return result;
}
생각할 수 있는 유일한 문제는 입력 문자열이 매우 긴 경우입니다.CharArray()를 호출하면 문자열의 내부 배열이 복사됩니다.
편집: 아, 덧붙여서 바이트는 Java로 서명되어 있기 때문에 입력 문자열은 [0, 160, 191]이 아닌 [0, -96, -65]로 변환됩니다.하지만 당신은 이미 알고 있었을 겁니다.
안드로이드에서는 16진수로 작업하는 경우 okio를 사용할 수 있습니다.
간단한 사용법:
byte[] bytes = ByteString.decodeHex("c000060000").toByteArray();
그리고 그 결과는
[-64, 0, 6, 0, 0]
BigInteger()수 없습니다.java.math는 매우 느립니다.
Integer.parseInt(HEXString, 16)
숫자/정수로 변환하지 않으면 일부 문자에 문제가 발생할 수 있습니다.
Well Working 방법:
Integer.decode("0xXX") .byteValue()
기능:
public static byte[] HexStringToByteArray(String s) {
byte data[] = new byte[s.length()/2];
for(int i=0;i < s.length();i+=2) {
data[i/2] = (Integer.decode("0x"+s.charAt(i)+s.charAt(i+1))).byteValue();
}
return data;
}
즐거운 시간 되세요, 행운을 빌어요
EDIT: @myers에서 지적한 바와 같이 이 메서드는 높은 비트('80' - 'FF')가 설정된 바이트에 대응하는 기판을 포함하는 입력에서는 작동하지 않습니다.설명은 Bug ID: 6259307 Byte.parseByte가 SDK Documentation에서 광고한 대로 작동하지 않습니다.
public static final byte[] fromHexString(final String s) {
byte[] arr = new byte[s.length()/2];
for ( int start = 0; start < s.length(); start += 2 )
{
String thisByte = s.substring(start, start+2);
arr[start/2] = Byte.parseByte(thisByte, 16);
}
return arr;
}
중요한 것은 문자열 연결에 의존하지 않고 홀수 길이의 문자열을 지원하는 다른 버전입니다.
public static byte[] hexStringToByteArray(String input) {
int len = input.length();
if (len == 0) {
return new byte[] {};
}
byte[] data;
int startIdx;
if (len % 2 != 0) {
data = new byte[(len / 2) + 1];
data[0] = (byte) Character.digit(input.charAt(0), 16);
startIdx = 1;
} else {
data = new byte[len / 2];
startIdx = 0;
}
for (int i = startIdx; i < len; i += 2) {
data[(i + 1) / 2] = (byte) ((Character.digit(input.charAt(i), 16) << 4)
+ Character.digit(input.charAt(i+1), 16));
}
return data;
}
저는 Character.digit 솔루션을 좋아하지만, 이렇게 해결했습니다.
public byte[] hex2ByteArray( String hexString ) {
String hexVal = "0123456789ABCDEF";
byte[] out = new byte[hexString.length() / 2];
int n = hexString.length();
for( int i = 0; i < n; i += 2 ) {
//make a bit representation in an int of the hex value
int hn = hexVal.indexOf( hexString.charAt( i ) );
int ln = hexVal.indexOf( hexString.charAt( i + 1 ) );
//now just shift the high order nibble and add them together
out[i/2] = (byte)( ( hn << 4 ) | ln );
}
return out;
}
나는 항상 다음과 같은 방법을 사용해 왔다.
public static final byte[] fromHexString(final String s) {
String[] v = s.split(" ");
byte[] arr = new byte[v.length];
int i = 0;
for(String val: v) {
arr[i++] = Integer.decode("0x" + val).byteValue();
}
return arr;
}
이 메서드는 공백으로 구분된 16진수 값으로 분할되지만 다른 기준(예: 2글자 그룹화)으로 문자열을 분할하는 것은 어렵지 않습니다.
Bert Regelink에 의해 제시된 코드는 단순히 작동하지 않습니다.다음을 시도해 보십시오.
import javax.xml.bind.DatatypeConverter;
import java.io.*;
public class Test
{
@Test
public void testObjectStreams( ) throws IOException, ClassNotFoundException
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
String stringTest = "TEST";
oos.writeObject( stringTest );
oos.close();
baos.close();
byte[] bytes = baos.toByteArray();
String hexString = DatatypeConverter.printHexBinary( bytes);
byte[] reconvertedBytes = DatatypeConverter.parseHexBinary(hexString);
assertArrayEquals( bytes, reconvertedBytes );
ByteArrayInputStream bais = new ByteArrayInputStream(reconvertedBytes);
ObjectInputStream ois = new ObjectInputStream(bais);
String readString = (String) ois.readObject();
assertEquals( stringTest, readString);
}
}
Kernel Panic이 가장 유용한 솔루션을 제공하지만 16진수 문자열이 홀수일 경우 문제가 발생하였습니다.다음과 같이 해결했습니다.
boolean isOdd(int value)
{
return (value & 0x01) !=0;
}
private int hexToByte(byte[] out, int value)
{
String hexVal = "0123456789ABCDEF";
String hexValL = "0123456789abcdef";
String st = Integer.toHexString(value);
int len = st.length();
if (isOdd(len))
{
len+=1; // need length to be an even number.
st = ("0" + st); // make it an even number of chars
}
out[0]=(byte)(len/2);
for (int i =0;i<len;i+=2)
{
int hh = hexVal.indexOf(st.charAt(i));
if (hh == -1) hh = hexValL.indexOf(st.charAt(i));
int lh = hexVal.indexOf(st.charAt(i+1));
if (lh == -1) lh = hexValL.indexOf(st.charAt(i+1));
out[(i/2)+1] = (byte)((hh << 4)|lh);
}
return (len/2)+1;
}
배열에 16진수 숫자를 추가하고 있기 때문에 사용 중인 배열에 참조를 전달하고 필요한 int를 변환하여 다음 16진수의 상대 위치를 반환합니다.따라서 마지막 바이트 배열에는 [0]개의 16진수 쌍이 있고 [1...]개의 16진수 쌍이 있으며, 그 다음 쌍의 수가...
op 투표 솔루션에 근거해, 다음의 작업이 보다 효율적입니다.
public static byte [] hexStringToByteArray (final String s) {
if (s == null || (s.length () % 2) == 1)
throw new IllegalArgumentException ();
final char [] chars = s.toCharArray ();
final int len = chars.length;
final byte [] data = new byte [len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit (chars[i], 16) << 4) + Character.digit (chars[i + 1], 16));
}
return data;
}
이유: char 배열로 초기 변환 시 charAt에 길이 체크가 없습니다.
코딩 스타일로 Java 8 스트림을 선호하는 경우 JDK 프리미티브만 사용하여 이 작업을 수행할 수 있습니다.
String hex = "0001027f80fdfeff";
byte[] converted = IntStream.range(0, hex.length() / 2)
.map(i -> Character.digit(hex.charAt(i * 2), 16) << 4 | Character.digit(hex.charAt((i * 2) + 1), 16))
.collect(ByteArrayOutputStream::new,
ByteArrayOutputStream::write,
(s1, s2) -> s1.write(s2.toByteArray(), 0, s2.size()))
.toByteArray();
그, 0, s2.size()collector concontainate 함수의 파라미터는 캐치해도 괜찮다면 생략할 수 있습니다.IOException.
public static byte[] hex2ba(String sHex) throws Hex2baException {
if (1==sHex.length()%2) {
throw(new Hex2baException("Hex string need even number of chars"));
}
byte[] ba = new byte[sHex.length()/2];
for (int i=0;i<sHex.length()/2;i++) {
ba[i] = (Integer.decode(
"0x"+sHex.substring(i*2, (i+1)*2))).byteValue();
}
return ba;
}
공식 솔루션:
/**
* Decodes a hexadecimally encoded binary string.
* <p>
* Note that this function does <em>NOT</em> convert a hexadecimal number to a
* binary number.
*
* @param hex Hexadecimal representation of data.
* @return The byte[] representation of the given data.
* @throws NumberFormatException If the hexadecimal input string is of odd
* length or invalid hexadecimal string.
*/
public static byte[] hex2bin(String hex) throws NumberFormatException {
if (hex.length() % 2 > 0) {
throw new NumberFormatException("Hexadecimal input string must have an even length.");
}
byte[] r = new byte[hex.length() / 2];
for (int i = hex.length(); i > 0;) {
r[i / 2 - 1] = (byte) (digit(hex.charAt(--i)) | (digit(hex.charAt(--i)) << 4));
}
return r;
}
private static int digit(char ch) {
int r = Character.digit(ch, 16);
if (r < 0) {
throw new NumberFormatException("Invalid hexadecimal string: " + ch);
}
return r;
}
PHP hex2bin() 함수와 비슷하지만 Java 스타일입니다.
예:
String data = new String(hex2bin("6578616d706c65206865782064617461"));
// data value: "example hex data"
파티에는 늦었지만, 혹시 도움이 될까 봐 DaveL의 답변을 역액션과 함께 클래스로 통합했습니다.
public final class HexString {
private static final char[] digits = "0123456789ABCDEF".toCharArray();
private HexString() {}
public static final String fromBytes(final byte[] bytes) {
final StringBuilder buf = new StringBuilder();
for (int i = 0; i < bytes.length; i++) {
buf.append(HexString.digits[(bytes[i] >> 4) & 0x0f]);
buf.append(HexString.digits[bytes[i] & 0x0f]);
}
return buf.toString();
}
public static final byte[] toByteArray(final String hexString) {
if ((hexString.length() % 2) != 0) {
throw new IllegalArgumentException("Input string must contain an even number of characters");
}
final int len = hexString.length();
final byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(hexString.charAt(i), 16) << 4)
+ Character.digit(hexString.charAt(i + 1), 16));
}
return data;
}
}
JUnit 테스트 클래스:
public class TestHexString {
@Test
public void test() {
String[] tests = {"0FA1056D73", "", "00", "0123456789ABCDEF", "FFFFFFFF"};
for (int i = 0; i < tests.length; i++) {
String in = tests[i];
byte[] bytes = HexString.toByteArray(in);
String out = HexString.fromBytes(bytes);
System.out.println(in); //DEBUG
System.out.println(out); //DEBUG
Assert.assertEquals(in, out);
}
}
}
이게 아주 오래된 이야기라는 걸 알지만, 그래도 내 한 푼의 가치를 더하고 싶어.
굳이 16진수 문자열을 바이너리 변환기로 코드화할 필요가 있다면 다음과 같이 하고 싶습니다.
public static byte[] hexToBinary(String s){
/*
* skipped any input validation code
*/
byte[] data = new byte[s.length()/2];
for( int i=0, j=0;
i<s.length() && j<data.length;
i+=2, j++)
{
data[j] = (byte)Integer.parseInt(s.substring(i, i+2), 16);
}
return data;
}
필요에 따라서는 HexUtils를 사용할 수 있습니다.
예:
byte[] byteArray = Hex.hexStrToBytes("00A0BF");
이것은 가장 간단한 경우입니다.입력에 딜리미터(MAC 주소, 증명서 지문 등)가 포함되어 있을 수 있습니다.입력 내용은 스트리밍일 수 있습니다.이러한 경우 아무리 작더라도 HexUtils와 같은 외부 라이브러리를 끌어오는 것이 정당화될 수 있습니다.
JDK 17을 사용하면 HexFormat 클래스는 대부분의 요구를 충족시킬 수 있으며 HexUtils 등의 요구는 크게 줄어듭니다.그러나 HexUtils는 JDK HexFormat 클래스가 할 수 없는 매우 많은 양의 16진수 변환(스트리밍)이나 예쁜 인쇄 16진수 변환(와이어 덤프라고 생각)에 사용할 수 있습니다.
(완전 공개:저는 Hex Utils의 저자입니다.)
당신을 위해 할 수 있을 것 같아요.데이터를 문자열로 반환하는 유사한 함수에서 함께 만들었습니다.
private static byte[] decode(String encoded) {
byte result[] = new byte[encoded/2];
char enc[] = encoded.toUpperCase().toCharArray();
StringBuffer curr;
for (int i = 0; i < enc.length; i += 2) {
curr = new StringBuffer("");
curr.append(String.valueOf(enc[i]));
curr.append(String.valueOf(enc[i + 1]));
result[i] = (byte) Integer.parseInt(curr.toString(), 16);
}
return result;
}
저에겐 HEX=라는 솔루션이 있었습니다."다음으로 FF01"을 FF(255)와 01(01)로 분할합니다.
private static byte[] BytesEncode(String encoded) {
//System.out.println(encoded.length());
byte result[] = new byte[encoded.length() / 2];
char enc[] = encoded.toUpperCase().toCharArray();
String curr = "";
for (int i = 0; i < encoded.length(); i=i+2) {
curr = encoded.substring(i,i+2);
System.out.println(curr);
if(i==0){
result[i]=((byte) Integer.parseInt(curr, 16));
}else{
result[i/2]=((byte) Integer.parseInt(curr, 16));
}
}
return result;
}
언급URL : https://stackoverflow.com/questions/140131/convert-a-string-representation-of-a-hex-dump-to-a-byte-array-using-java
'programing' 카테고리의 다른 글
| 왜 일찍 돌아오는 것이 다른 것보다 느리죠? (0) | 2022.11.23 |
|---|---|
| 전체 MySQL 데이터베이스에 대한 모든 외부 키 제약 조건 보기 (0) | 2022.11.14 |
| JavaScript에서 이메일을 보내는 방법 (0) | 2022.11.14 |
| javascript에서 포커스를 지우려면 어떻게 해야 하나요? (0) | 2022.11.14 |
| 텍스트 입력 필드에서 Enter 키를 검출합니다. (0) | 2022.11.14 |