hex 덤프의 문자열 표현을 Java를 사용하여 바이트 어레이로 변환 하시겠습니까?
문제
16 진수를 바이트 배열로 나타내는 긴 문자열 (덤프에서)을 변환하는 방법을 찾고 있습니다.
게시 한 사람보다 더 잘 표현할 수 없었습니다. 여기에도 같은 질문이 있습니다.
하지만 원래를 유지하려면 내 자신의 방식으로 표현할 것입니다. 내가 끈이 있다고 가정 해 "00A0BF"
내가 해석하고 싶다
byte[] {0x00,0xA0,0xBf}
어떻게해야합니까?
나는 Java 초보자이고 결국 사용했습니다 BigInteger
그리고 선도적 인 16 진수를 관찰합니다. 그러나 나는 그것이 추악하다고 생각하고 나는 간단한 것을 놓치고 있다고 확신합니다.
해결책
다음은 지금까지 게시 된 어느 것보다 낫다고 생각하는 솔루션입니다.
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[]
, 또는 모든 바이트에 대해 StringBuilder 및 String 객체를 작성하십시오.사용할 수없는 라이브러리 의존성이 없습니다
용기 확인을 통해 자유롭게 추가하십시오 assert
또는 논증이 안전한 것으로 알려지지 않은 경우 예외.
다른 팁
1 라이너 :
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);
}
경고:
- Java 9 Jigsaw에서 이것은 더 이상 (기본값) java.se 루트 세트의 일부가 아니므로 -add-modules java.se.ee를 지정하지 않는 한 classNotFoundException이 발생합니다 ( @ 덕분
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
이제 사용할 수 있습니다 베이스 코딩 안에 guava
이것을 달성하기 위해.
BaseEncoding.base16().decode(string);
그것을 반전하려면 사용합니다
BaseEncoding.base16().encode(bytes);
사실, 나는 biginteger가 솔루션이라고 생각합니다.
new BigInteger("00A0BF", 16).toByteArray();
편집하다: 주요 0에 안전하지 않습니다, 포스터에서 언급 한 바와 같이.
그만큼 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;
}
그것은 내가 입력 한 예일뿐입니다 ... 실제로 그대로 사용하고 사용하기위한 별도의 방법을 만들 필요가 없습니다.
1 라이너 :
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); }
뒤의 실제 코드에 관심이있는 사람들을 위해 1 라이너 ~에서 프랙탈 라이저 (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();
}
다음은 실제로 작동하는 메소드입니다 (이전의 몇 가지 반 수정 답변을 기반으로) :
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;
}
내가 볼 수있는 유일한 문제는 입력 문자열이 매우 길면; tochararray () 호출은 문자열의 내부 배열 사본을 만듭니다.
편집 : 아, 그리고 그건 그렇고, 바이트는 Java로 서명되므로 입력 문자열은 [0, 160, 191] 대신 [0, -96, -65]로 변환됩니다. 그러나 당신은 아마 이미 그것을 알고 있었을 것입니다.
Android에서는 16 진수로 작업하는 경우 시도해 볼 수 있습니다. 오키오.
간단한 사용 :
byte[] bytes = ByteString.decodeHex("c000060000").toByteArray();
그리고 결과가 될 것입니다
[-64, 0, 6, 0, 0]
편집 : @mmyers가 지적한 바와 같이,이 방법은 높은 비트 세트 ( "80" - "FF")가있는 바이트에 해당하는 하위 문자열이 포함 된 입력에서 작동하지 않습니다. 설명이 있습니다 버그 ID : 6259307 byte.parsebyte SDK 문서에 광고 된대로 작동하지 않습니다..
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;
}
그만큼 BigInteger()
java.math의 메소드는 매우 느리고 권장 할 수 없습니다.
Integer.parseInt(HEXString, 16)
Digit / Integer로 변환하지 않고 일부 문자에 문제가 발생할 수 있습니다.
잘 작동하는 방법 :
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;
}
재미, 행운을 빕니다
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);
}
}
가치가있는 것에 대해, 여기에는 문자열 연결에 의지하지 않고 홀수 길이 문자열을 지원하는 또 다른 버전이 있습니다.
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;
}
나는 항상 같은 방법을 사용했습니다
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 진수 값에 나뉘지만 두 문자 그룹으로 문자열을 분할하는 것은 어렵지 않습니다.
나는 캐릭터를 좋아한다. 디지털 솔루션이지만 여기에 내가 그것을 해결 한 방법은 다음과 같습니다.
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;
}
나는 커널 공황이 나에게 가장 유용한 솔루션을 갖는 것을 발견했지만 육각 문자열이 홀수 인 경우 문제가 발생했습니다. 이런 식으로 해결했습니다.
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 진수를 추가하고 있으므로 사용중인 배열에 대한 참조를 전달하고 다음 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;
}
왜냐하면 : 숯 배열로의 초기 변환은 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()
잡기를 신경 쓰지 않으면 수집기 연결 기능의 매개 변수를 생략 할 수 있습니다. 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 () 함수 그러나 자바 스타일로.
예시:
String data = new String(hex2bin("6578616d706c65206865782064617461"));
// data value: "example hex data"
가장 깨끗한 솔루션은 아닙니다. 그러나 그것은 나에게 효과적이며 잘 형식화되어 있습니다.
private String createHexDump(byte[] msg, String description) {
System.out.println();
String result = "\n" + description;
int currentIndex = 0;
for(int i=0 ; i<msg.length ; i++){
currentIndex++;
if(i == 0){
result += String.format("\n %04x ", i);
}
if(i % 16 == 0 && i != 0){
result += " | ";
for(int j=(i-16) ; j<msg.length && j<i ; j++) {
char characterToAdd = (char) msg[j];
if (characterToAdd == '\n') {
characterToAdd = ' ';
}
result += characterToAdd;
}
result += String.format("\n %04x ", i);
}
result += String.format("%02x ", msg[i]);
}
if(currentIndex % 16 != 0){
int fitIns = msg.length / 16;
int leftOvers = msg.length - (fitIns * 16);
for(int i=0 ; i<16-leftOvers ; i++){
result += " ";
}
result += " | ";
for(int i=msg.length-leftOvers ; i<msg.length ; i++){
char characterToAdd = (char) msg[i];
if (characterToAdd == '\n') {
characterToAdd = ' ';
}
result += characterToAdd;
}
}
result += "\n";
return result;
}
출력 :
S -> C
0000 0b 00 2e 06 4d 6f 72 69 74 7a 53 6f 6d 65 20 54 | .Heyyy Some T
0010 43 50 20 73 74 75 66 66 20 49 20 63 61 70 74 75 | CP stuff I captu
0020 72 65 64 2e 2e 77 65 6c 6c 20 66 6f 72 6d 61 74 | red..well format
0030 3f | ?
파티에 늦었지만, 나는 Davel의 위의 답변을 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 Test 클래스 :
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);
}
}
}
나는 이것이 아주 오래된 실이라는 것을 알고 있지만 여전히 내 페니 가치를 추가하고 싶습니다.
간단한 육각 문자열을 바이너리 컨버터로 코딩 해야하는 경우 다음과 같이 수행하고 싶습니다.
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;
}
나는 당신을 위해 그것을 할 것이라고 생각합니다. 데이터를 문자열로 반환 한 비슷한 함수에서 함께 모았습니다.
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;
}