Java kodu Baytı Onaltılık biçime dönüştürmek için


184

Bir bayt dizim var. Bu dizinin her bayt dizesini karşılık gelen onaltılık değerlerine dönüştürülmesini istiyorum.

Java'da bir bayt dizisini Onaltılık biçime dönüştürmek için herhangi bir işlev var mı?


2
Java'da bayt dizisi olarak adlandırdığınız dilde diğer dillerde bayt dizesi denir (örn. Docs.racket-lang.org/guide/bytestrings.html )
Patrick Favre

Yanıtlar:


311
    byte[] bytes = {-1, 0, 1, 2, 3 };
    StringBuilder sb = new StringBuilder();
    for (byte b : bytes) {
        sb.append(String.format("%02X ", b));
    }
    System.out.println(sb.toString());
    // prints "FF 00 01 02 03 "

Ayrıca bakınız

  • java.util.Formatter sözdizimi
    • %[flags][width]conversion
      • İşaretle '0'- Sonuç sıfır dolgulu olacak
      • Genişlik 2
      • Dönüşüm 'X'- Sonuç, onaltılık bir tam sayı, büyük harf olarak biçimlendirilir

Sorunun metnine bakıldığında, istenen de bu olabilir:

    String[] arr = {"-1", "0", "10", "20" };
    for (int i = 0; i < arr.length; i++) {
        arr[i] = String.format("%02x", Byte.parseByte(arr[i]));
    }
    System.out.println(java.util.Arrays.toString(arr));
    // prints "[ff, 00, 0a, 14]"

Burada birkaç cevap kullanır Integer.toHexString(int); bu yapılabilir, ancak bazı uyarılarla. Parametre bir intolduğundan, bytebağımsız değişkene işaret uzantısını içeren genişleyen bir ilkel dönüşüm gerçekleştirilir .

    byte b = -1;
    System.out.println(Integer.toHexString(b));
    // prints "ffffffff"

byteJava'da imzalanan 8 bit , işaret 32 ​​bit olarak genişletilmiştir int. Bu işaret uzantısını etkili bir şekilde geri almak için, byteile maskelenebilir 0xFF.

    byte b = -1;
    System.out.println(Integer.toHexString(b & 0xFF));
    // prints "ff"

Kullanmayla ilgili başka bir sorun toHexString, sıfırlarla doldurulmamasıdır:

    byte b = 10;
    System.out.println(Integer.toHexString(b & 0xFF));
    // prints "a"

Birleştirilen her iki faktör de String.formatçözümü daha tercih edilir hale getirmelidir .

Referanslar


@Vivek: "çok büyük bir değer" nedir? Girdi nedir ve çıktı nedir?
poligeno

Tekrar açıklayayım .. Ben bir dizi bayt dizeleri bir koleksiyon var. Ama ne yapmak zorunda her bayt ayrı ayrı analiz .. Yani, ben bütün dizi üzerinde çalışmak istemiyorum, ama bir seferde bireysel bayt dize, bu dizinin bir bileşenidir .. kelimesi nedeniyle ortaya çıkan karışıklık " dizi". Şimdi aşağıdaki kodda "byte bv = 10; Dize hexString = Integer.toHexString (bv);" CAse 1 (Bayt Alındı: 68 Onaltılı Çıktı:: 44) Durum: 2 (Bayt Alındı: -46 Onaltılı Çıktı:: ffffffd2) ......... Neden bazı değerler için bu kadar beklenmedik bir sonuç elde ediyorum?
Vivek

1
@Vivek: kullanma hakkındaki cevabımı oku toHexString. Sen ile maskelemek zorunda & 0xFF, yani Integer.toHexString(-46 & 0xFF)bir "d2".
poligeno

@polygenelubricants: Çok teşekkürler .. Görünüşe göre, kod iyi çalışıyor .. Şimdi toHexString işlevini kullanmak güvenli mi? Veya yaklaşımda boşluklar olabilir mi?
Vivek

1
@Vivek: "güvenli", sadece dikkatli olmanız ve bytedeğeri & 0xFFher seferinde maskelediğinizden emin olmanız gerekir . formatYukarıdaki çözüm ayrıca aslında argüman olarak kullanmakta olduğunuz bağlı maskeleme gerektirebilir.
poligeno

65

Gönderiyorum, çünkü mevcut cevapların hiçbiri yaklaşımlarının neden işe yaradığını açıklamıyor, bence bu sorun için gerçekten önemli. Bazı durumlarda, bu önerilen çözümün gereksiz yere karmaşık ve ince görünmesine neden olur. Göstermek için oldukça basit bir yaklaşım sunacağım, ancak neden işe yaradığını göstermeye yardımcı olmak için biraz daha ayrıntı vereceğim .

Öncelikle ne yapmaya çalışıyoruz? Bir bayt değerini (veya bayt dizisini) ASCII'de onaltılık bir değeri temsil eden bir dizeye dönüştürmek istiyoruz. Birinci adım, Java'daki bir baytın tam olarak ne olduğunu bulmaktır:

Bayt veri türü, 8-bit imzalı ikinin tamamlayıcı tamsayısıdır . Minimum değeri -128 ve maksimum değeri 127 (dahil )'dir. Bayt veri türü, bellek tasarrufunun gerçekten önemli olduğu büyük dizilerde bellek tasarrufu için yararlı olabilir. Sınırlarının kodunuzu netleştirmeye yardımcı olduğu int yerine de kullanılabilirler; bir değişkenin aralığının sınırlı olması bir belge biçimi olarak kullanılabilir.

Ne anlama geliyor? Birkaç şey: Birincisi ve en önemlisi, 8 bit ile çalıştığımız anlamına geliyor . Örneğin, 2 sayısını 0000 0010 olarak yazabiliriz. Bununla birlikte, ikisinin tamamlayıcısı olduğundan, bunun gibi bir negatif 2 yazıyoruz: 1111 1110. Bunun anlamı, hex'e dönüştürmenin çok basit olmasıdır. Yani, her bir 4 bit segmenti doğrudan hex'e dönüştürürsünüz. Bu şemadaki negatif sayıları anlamak için önce ikisinin tamamlayıcısını anlamanız gerektiğini unutmayın. Zaten ikisinin tamamlayıcısını anlamadıysanız, burada mükemmel bir açıklama okuyabilirsiniz: http://www.cs.cornell.edu/~tomf/notes/cps104/twoscomp.html


İkinin Tamamlayıcısını Genel Olarak Hex'e Dönüştürme

Bir sayı ikinin tamamlayıcısında olduğunda, hex'e dönüştürmek basittir. Genel olarak, ikilikten onaltılıya dönüştürme çok basittir ve sonraki iki örnekte göreceğiniz gibi, doğrudan ikinin tamamlayıcısından onaltılıya gidebilirsiniz.

Örnekler

Örnek 1: 2'yi Hex'e dönüştürün.

1) Önce ikisinin tamamlayıcısında 2'yi ikiliye dönüştürün:

2 (base 10) = 0000 0010 (base 2)

2) Şimdi ikiliyi onaltılık biçime dönüştürün:

0000 = 0x0 in hex
0010 = 0x2 in hex

therefore 2 = 0000 0010 = 0x02. 

Örnek 2: -2'yi (ikisinin tamamlayıcısında) Hex'e dönüştürün.

1) Önce ikisinin tamamlayıcısında -2'yi ikiliye dönüştürün:

-2 (base 10) = 0000 0010 (direct conversion to binary) 
               1111 1101 (invert bits)
               1111 1110 (add 1)
therefore: -2 = 1111 1110 (in two's complement)

2) Şimdi Hex'e Dönüştür:

1111 = 0xF in hex
1110 = 0xE in hex

therefore: -2 = 1111 1110 = 0xFE.


Java ile bunu yapmak

Şimdi konsepti ele aldığımıza göre, istediğimiz şeyi basit bir maskeleme ve kaydırma ile başarabileceğimizi göreceksiniz. Anlaşılması gereken en önemli şey, dönüştürmeye çalıştığınız baytın zaten ikisinin tamamlayıcısı olması. Bu dönüşümü kendiniz yapmazsınız. Sanırım bu, bu konuda büyük bir karışıklık noktası. Örneğin aşağıdaki bayt dizisini ele alalım:

byte[] bytes = new byte[]{-2,2};

Bunları manuel olarak yukarıdaki hex'e dönüştürdük, ancak Java'da nasıl yapabiliriz? Bunu nasıl yapacağınız aşağıda açıklanmıştır:

Adım 1: Hesaplamamız için bir StringBuffer oluşturun.

StringBuffer buffer = new StringBuffer();

Adım 2: Yüksek dereceli bitleri ayırın, onaltılık biçime dönüştürün ve arabelleğe ekleyin

1111 1110 ikili sayısı göz önüne alındığında, yüksek dereceli bitleri önce 4'e kaydırarak ve sonra sayının geri kalanını sıfırlayarak ayırabiliriz. Mantıksal olarak bu basittir, ancak Java'daki uygulama ayrıntıları (ve birçok dilde) işaret uzantısı nedeniyle bir kırışıklık yaratır. Temel olarak, bir bayt değerini kaydırdığınızda, Java önce değerinizi bir tamsayıya dönüştürür ve ardından işaret uzantısını gerçekleştirir. Yani 1111 1110 >> 4'ün 0000 1111 olmasını beklerken, gerçekte Java'da ikisinin tamamlayıcısı 0xFFFFFFFF olarak temsil edilir!

Yani örneğimize geri dönersek:

1111 1110 >> 4 (shift right 4) = 1111 1111 1111 1111 1111 1111 1111 1111 (32 bit sign-extended number in two's complement)

Daha sonra bitleri bir maske ile izole edebiliriz:

1111 1111 1111 1111 1111 1111 1111 1111 & 0xF = 0000 0000 0000 0000 0000 0000 0000 1111
therefore: 1111 = 0xF in hex. 

Java ile tüm bunları tek seferde yapabiliriz:

Character.forDigit((bytes[0] >> 4) & 0xF, 16);

ForDigit işlevi, 0-F onaltılık sayılar kümesine ilettiğiniz sayıyı eşleştirir.

Adım 3: Sonra, daha düşük sipariş bitlerini izole etmeliyiz. İstediğimiz bitler zaten doğru konumda olduğundan, onları maskeleyebiliriz:

1111 1110 & 0xF = 0000 0000 0000 0000 0000 0000 0000 1110 (recall sign extension from before)
therefore: 1110 = 0xE in hex.  

Daha önce olduğu gibi, Java'da bunları tek bir seferde yapabiliriz:

Character.forDigit((bytes[0] & 0xF), 16);

Bunu bir araya getirerek for döngüsü olarak yapabilir ve tüm diziyi dönüştürebiliriz:

for(int i=0; i < bytes.length; i++){
    buffer.append(Character.forDigit((bytes[i] >> 4) & 0xF, 16));
    buffer.append(Character.forDigit((bytes[i] & 0xF), 16));
}

Umarım bu açıklama, internette bulacağınız birçok örnekte neler olup bittiğini merak edenler için işleri daha net hale getirir. Umarım berbat hatalar yapmadım, ancak öneriler ve düzeltmeler son derece açıktır!


4
en iyi cevap! Byte bir onaltılık dize ait simetrik uygulama daha sonra dönüşüm kullanırsınız Character.digit()gibi(byte) ((Character.digit(str.charAt(0), 16) << 4) + Character.digit(str.charAt(1), 16))
ericbn

21

Bunu yapmanın en hızlı yolu şudur:

private static final String    HEXES    = "0123456789ABCDEF";

static String getHex(byte[] raw) {
    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();
}

Bundan ~ 50 kat daha hızlı String.format. test etmek istiyorsanız:

public class MyTest{
    private static final String    HEXES        = "0123456789ABCDEF";

    @Test
    public void test_get_hex() {
        byte[] raw = {
            (byte) 0xd0, (byte) 0x0b, (byte) 0x01, (byte) 0x2a, (byte) 0x63,
            (byte) 0x78, (byte) 0x01, (byte) 0x2e, (byte) 0xe3, (byte) 0x6c,
            (byte) 0xd2, (byte) 0xb0, (byte) 0x78, (byte) 0x51, (byte) 0x73,
            (byte) 0x34, (byte) 0xaf, (byte) 0xbb, (byte) 0xa0, (byte) 0x9f,
            (byte) 0xc3, (byte) 0xa9, (byte) 0x00, (byte) 0x1e, (byte) 0xd5,
            (byte) 0x4b, (byte) 0x89, (byte) 0xa3, (byte) 0x45, (byte) 0x35,
            (byte) 0xd6, (byte) 0x10,
        };

        int N = 77777;
        long t;

        {
            t = System.currentTimeMillis();
            for (int i = 0; i < N; i++) {
                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)));
                }
                hex.toString();
            }
            System.out.println(System.currentTimeMillis() - t); // 50
        }

        {
            t = System.currentTimeMillis();
            for (int i = 0; i < N; i++) {
                StringBuilder hex = new StringBuilder(2 * raw.length);
                for (byte b : raw) {
                    hex.append(String.format("%02X", b));
                }
                hex.toString();
            }
            System.out.println(System.currentTimeMillis() - t); // 2535
        }

    }
}

Düzenleme : Sadece bir şey daha hızlı lil bulundu ve bir satırda tutar ama JRE 9 ile uyumlu değildir .

import javax.xml.bind.DatatypeConverter;

DatatypeConverter.printHexBinary(raw);

2
DatatypeConverter artık Java 9'da kullanılamıyor. Tehlikeli olan, onu kullanan kod Java 1.8 veya öncesi altında derlenecek (kaynak ayarlarına sahip Java 9 önceki sürümlerde), ancak Java 9 altında bir çalışma zamanı istisnası olsun.
Stephen M -on strike-

Ben ikinci @StephenMs nokta: jre9 ile bunu kullanarak ClassNotFound İstisna
Patrick Favre

Aslında sadece printHexBinary 1 yöntemden 1 kat daha hızlı görünüyor jdk src.zip kaynak kodu yöntemini ayıklayabilirsiniz .
Meyve

1
Dize ve charAt () yerine HEXES sabiti için char dizisi ile çalışırsanız, ~% 20 daha fazla hız kazanırsınız.
Dyorgio

15

Bu şekilde deneyin:

byte bv = 10;
String hexString = Integer.toHexString(bv);

Dizi ile başa çıkmak (eğer doğru anladıysam):

byte[] bytes = {9, 10, 11, 15, 16};
StringBuffer result = new StringBuffer();
for (byte b : bytes) {
    result.append(String.format("%02X ", b));
    result.append(" "); // delimiter
}
return result.toString();

Poligeno-yağlayıcıların belirttiği gibi String.format(), doğru cevaptır Integer.toHexString()(negatif sayıları doğru bir şekilde ele aldığından).


2
Bu, uzatmayı işaret edecektir, örneğin deneyin -1.
poligeno

bayt bv = 10; String hexString = Integer.toHexString (bv); Bu firne işe benziyor .. Ben dizinin her elemanına ayrı ayrı uygulayabilirsiniz .. Diğer kod (dizi ile başa çıkmak) geri çok büyük bir değer verir. Bunun nedeni ne olabilir?
Vivek

@Vivek, bunun nedeni tek bir onaltılık karakterbv döndürmesi . Oysa kodun geri kalanı onaltılık karakterlerden oluşan bir dize döndürür . Şimdi anlayabilmeniz için kodu sınırlayıcı ile değiştirdim.
0x2D9A3

@Bar: İşaret uzantısını geri almak Integer.toHexStringiçin byteile maskelerseniz yine de kullanabilirsiniz 0xFF.
poligeno

CAse 1 (Bayt Alındı: 68 Onaltılı Çıktı:: 44) Kasa: 2 (Bayt Alındı: -46 Onaltılı Çıktı:: ffffffd2) Negatif bayt dizileri olması durumunda beklenmedik çıkış değerleri alıyorum ... Bu nasıl yapılır?
Vivek

13

En iyi çözüm bu badass tek astarlı:

String hex=DatatypeConverter.printHexBinary(byte[] b);

burada belirtildiği gibi


4
DatatypeConverter artık Java 9'da kullanılamıyor. Tehlikeli olan, onu kullanan kod Java 1.8 veya öncesi altında derlenecek (kaynak ayarlarına sahip Java 9 önceki sürümlerde), ancak Java 9 altında bir çalışma zamanı istisnası olsun.
Stephen M -on strike-

Onun dediği zaman üzgün değil jdk9. new BigInteger(byteArray).toString(16)o zaman gitmenin yolu. Onunla mükemmel sorunlar mı?
prayagupd

Belki mükemmel konular değil, ancak önde gelen sıfırları özleyecek (BigInteger gibi bir sayı için anlamsız oldukları için)
Friso

Hala java 9 belgelerinde görünüyor, bu yüzden hala söyleyebileceğim kadarıyla kullanmakta sorun yok
Brad Parks

Ben burada açıklandığı gibi hala java9 için kullanmak için Tamam, ama gelecekteki java sürümlerinde kaldırılacak düşünüyorum . ayrıca 2.3.0 sürümünden itibaren 'yeni' bağımsız jaxb modülü ile de kullanabileceksiniz .
lynx

11

Baytları açık bir şekilde kurtarabilmeniz için sabit genişlikli onaltılık bir temsili (ör. 0AYerine) Aistiyorsanız, şunu deneyin format():

StringBuilder result = new StringBuilder();
for (byte bb : byteArray) {
    result.append(String.format("%02X", bb));
}
return result.toString();

11

byte[]Kullanarak hex dizesine dönüştürmenin kısa ve basit bir yolu BigInteger:

import java.math.BigInteger;

byte[] bytes = new byte[] {(byte)255, 10, 20, 30};
String hex = new BigInteger(1, bytes).toString(16);
System.out.println(hex); // ff0a141e

Nasıl çalışır?

Yerleşik sistem sınıfı java.math.BigIntegersınıfı ( java.math.BigInteger ) ikili ve onaltılık verilerle uyumludur:

  • Onun BigInteger(signum=1, byte[])tarafından büyük bir tamsayı oluşturmak için bir yapıcı vardır byte[](ilk parametresini ayarlayın signum= 1negatif baytları doğru işlemek için)
  • BigInteger.toString(16)Büyük tamsayıyı onaltılı dizeye dönüştürmek için kullanın
  • Onaltılık sayıyı ayrıştırmak için - baştaki new BigInteger("ffa74b", 16)sıfırı doğru işlemez

Onaltılık sonuçta önde gelen sıfıra sahip olmak istiyorsanız , boyutunu kontrol edin ve gerekirse eksik sıfırı ekleyin:

if (hex.length() % 2 == 1)
    hex = "0" + hex;

notlar

Kullanım new BigInteger(1, bytes)yerine new BigInteger(bytes)Java "çünkü tasarım gereği kırık " ve byteveri türü bayt ancak imzalı minik tamsayılar [-128 ... 127] tutmaz. İlk bayt negatifse, BigIntegernegatif büyük bir tam sayı ilettiğinizi varsayar. Sadece 1ilk parametre ( signum=1) olarak iletin .

Onaltılıdanbyte[] geri dönüşe geçiş zor: bazen üretilen çıktıya önde gelen bir sıfır girer ve şu şekilde temizlenmelidir:

byte[] bytes = new BigInteger("ffa74b", 16).toByteArray();
if (bytes[0] == 0) {
    byte[] newBytes = new byte[bytes.length - 1];
    System.arraycopy(bytes, 1, newBytes, 0, newBytes.length);
    bytes = newBytes;
}

Son not, byte[]baştaki birkaç sıfır varsa, kaybolur.


1
Baştaki baytın ondalık değeri 16'dan düşükse, tek sayıda onaltılık karakter içeren bir dize alırsınız.
Alex Jorgenson

8

Harici bir kitaplık kullanmaktan memnunsanız, org.apache.commons.codec.binary.Hexsınıfın encodeHexa alan byte[]ve a döndüren bir yöntemi vardır char[]. Bu yöntemler, biçim seçeneğinden ÇOK daha hızlıdır ve dönüşümün ayrıntılarını içerir. Ayrıca decodeHexters dönüşüm için bir yöntem ile birlikte gelir .


4
Daha da kolay bir yol javax.xml.bind.DatatypeConverter / parseHexBinary ve printHexBinary yerleşik işlevlerini kullanmaktır. Bkz. Stackoverflow.com/questions/9655181/…
Alan Thompson

2
Bu seçeneğe + 1'leyin. Hex ayrıca bir byte [] alan ve bir String döndüren encodeHexString yöntemine sahiptir.
Mingjiang Shi

javaxad alanının her zaman kullanılabilir olmadığını unutmayın .
Mene

7

Yöntemi Bouncy Castle Provider kütüphanesinden kullanabilirsiniz:

org.bouncycastle.util.encoders.Hex.toHexString(byteArray);

Bouncy Castle Crypto paketi, şifreleme algoritmalarının Java uygulamasıdır. Bu kavanoz, JCE sağlayıcısını ve JDK 1.5 ila JDK 1.8 için Bouncy Castle Şifreleme API'leri için hafif API'yi içerir.

Maven bağımlılığı:

<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcprov-jdk15on</artifactId>
    <version>1.60</version>
</dependency>

veya Apache Commons Codec'ten :

org.apache.commons.codec.binary.Hex.encodeHexString(byteArray);

Apache Commons Codec paketi, Base64 ve Hexadecimal gibi çeşitli biçimler için basit kodlayıcı ve kod çözücüler içerir. Bu yaygın olarak kullanılan kodlayıcılara ve kod çözücülere ek olarak, kodek paketi ayrıca fonetik kodlama yardımcı programlarının bir koleksiyonunu tutar.

Maven bağımlılığı:

<dependency>
    <groupId>commons-codec</groupId>
    <artifactId>commons-codec</artifactId>
    <version>1.11</version>
</dependency>

Evet, bu en iyi çözümdür , ancak harici bir kütüphane gerektirir: Apache Commons Codec ( mvnrepository.com/artifact/commons-codec/commons-codec/1.11 ) veya BouncyCastle Provider ( mvnrepository.com/artifact/org.bouncycastle/bcprov- jdk15on / 1.60 )
Svetlin Nakov

5

Bu şimdiye kadar en hızlı çalıştırmak için bulduğum kod. 23 ms'de 32 uzunluktaki 109015 bayt dizide çalıştırdım. Bir VM'de çalıştırıyordum, bu yüzden çıplak metalde daha hızlı çalışacaktı.

public static final char[] HEX_DIGITS =         {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};

public static char[] encodeHex( final byte[] data ){
    final int l = data.length;
    final char[] out = new char[l<<1];
    for( int i=0,j=0; i<l; i++ ){
        out[j++] = HEX_DIGITS[(0xF0 & data[i]) >>> 4];
        out[j++] = HEX_DIGITS[0x0F & data[i]];
    }
    return out;
}

O zaman yapabilirsin

String s = new String( encodeHex(myByteArray) );

3
BigInteger n = new BigInteger(byteArray);
String hexa = n.toString(16));

Çalışmaz: BigInteger(byteArrayOf(-1, 2, 3, 4, 5)).toString(16)döner"-fdfcfbfb"
Martin Vysny

Bu doğru bir sonuç. '-1', '2' ... '5' baytlarıyla çalışıyorsunuz. Eğer '-1', '2' ... '5' değişmezi ile çalışmak istiyorsanız, bu baytların görselleştirmesi yoktur ( unicode.org ) dize değerleriyle çalışmalısınız.
Wender

Yanlış sonuç. Java bayt (int) 255imzası olduğundan -1 Java bayt değeri aslında 0xFF'dir (aynıdır ), bu nedenle sonuç olmalıdır FF02030405. Yukarıdaki @Jerinaw çözümünü denerseniz, bunun doğru çıktıyı yazdıracağını göreceksiniz. Ayrıca aşağıda Svetlin Nakov'un çözümüne bakın.
Martin Vysny

2

İşte baytı Onaltılık dönüştürmek için basit bir işlev

   private static String convertToHex(byte[] data) {
    StringBuffer buf = new StringBuffer();
    for (int i = 0; i < data.length; i++) {
        int halfbyte = (data[i] >>> 4) & 0x0F;
        int two_halfs = 0;
        do {
            if ((0 <= halfbyte) && (halfbyte <= 9))
                buf.append((char) ('0' + halfbyte));
            else
                buf.append((char) ('a' + (halfbyte - 10)));
            halfbyte = data[i] & 0x0F;
        } while(two_halfs++ < 1);
    }
    return buf.toString();
}

2

Diğerleri genel davayı ele aldı. Ancak bilinen bir formun bayt diziniz varsa, örneğin bir MAC adresi varsa, şunları yapabilirsiniz:

byte[] mac = { (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00 };

String str = String.format("%02X:%02X:%02X:%02X:%02X:%02X",
                           mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); 

1

StringPerformans bir sorunsa bir sürü örnek oluşturmak (ve yok etmek) iyi bir yol değildir.

Lütfen ifadeleri kontrol eden ayrıntılı (yinelenen) bağımsız değişkenleri yok sayın if. Bu (başka) eğitim amaçlıdır.

Full maven projesi: http://jinahya.googlecode.com/svn/trunk/com.googlecode.jinahya/hex-codec/

Kodlama ...

/**
 * Encodes a single nibble.
 *
 * @param decoded the nibble to encode.
 *
 * @return the encoded half octet.
 */
protected static int encodeHalf(final int decoded) {

    switch (decoded) {
        case 0x00:
        case 0x01:
        case 0x02:
        case 0x03:
        case 0x04:
        case 0x05:
        case 0x06:
        case 0x07:
        case 0x08:
        case 0x09:
            return decoded + 0x30; // 0x30('0') - 0x39('9')
        case 0x0A:
        case 0x0B:
        case 0x0C:
        case 0x0D:
        case 0x0E:
        case 0x0F:
            return decoded + 0x57; // 0x41('a') - 0x46('f')
        default:
            throw new IllegalArgumentException("illegal half: " + decoded);
    }
}


/**
 * Encodes a single octet into two nibbles.
 *
 * @param decoded the octet to encode.
 * @param encoded the array to which each encoded nibbles are written.
 * @param offset the offset in the array.
 */
protected static void encodeSingle(final int decoded, final byte[] encoded,
                                   final int offset) {

    if (encoded == null) {
        throw new IllegalArgumentException("null encoded");
    }

    if (encoded.length < 2) {
        // not required
        throw new IllegalArgumentException(
            "encoded.length(" + encoded.length + ") < 2");
    }

    if (offset < 0) {
        throw new IllegalArgumentException("offset(" + offset + ") < 0");
    }

    if (offset >= encoded.length - 1) {
        throw new IllegalArgumentException(
            "offset(" + offset + ") >= encoded.length(" + encoded.length
            + ") - 1");
    }

    encoded[offset] = (byte) encodeHalf((decoded >> 4) & 0x0F);
    encoded[offset + 1] = (byte) encodeHalf(decoded & 0x0F);
}


/**
 * Decodes given sequence of octets into a sequence of nibbles.
 *
 * @param decoded the octets to encode
 *
 * @return the encoded nibbles.
 */
protected static byte[] encodeMultiple(final byte[] decoded) {

    if (decoded == null) {
        throw new IllegalArgumentException("null decoded");
    }

    final byte[] encoded = new byte[decoded.length << 1];

    int offset = 0;
    for (int i = 0; i < decoded.length; i++) {
        encodeSingle(decoded[i], encoded, offset);
        offset += 2;
    }

    return encoded;
}


/**
 * Encodes given sequence of octets into a sequence of nibbles.
 *
 * @param decoded the octets to encode.
 *
 * @return the encoded nibbles.
 */
public byte[] encode(final byte[] decoded) {

    return encodeMultiple(decoded);
}

Decoding ...

/**
 * Decodes a single nibble.
 *
 * @param encoded the nibble to decode.
 *
 * @return the decoded half octet.
 */
protected static int decodeHalf(final int encoded) {

    switch (encoded) {
        case 0x30: // '0'
        case 0x31: // '1'
        case 0x32: // '2'
        case 0x33: // '3'
        case 0x34: // '4'
        case 0x35: // '5'
        case 0x36: // '6'
        case 0x37: // '7'
        case 0x38: // '8'
        case 0x39: // '9'
            return encoded - 0x30;
        case 0x41: // 'A'
        case 0x42: // 'B'
        case 0x43: // 'C'
        case 0x44: // 'D'
        case 0x45: // 'E'
        case 0x46: // 'F'
            return encoded - 0x37;
        case 0x61: // 'a'
        case 0x62: // 'b'
        case 0x63: // 'c'
        case 0x64: // 'd'
        case 0x65: // 'e'
        case 0x66: // 'f'
            return encoded - 0x57;
        default:
            throw new IllegalArgumentException("illegal half: " + encoded);
    }
}


/**
 * Decodes two nibbles into a single octet.
 *
 * @param encoded the nibble array.
 * @param offset the offset in the array.
 *
 * @return decoded octet.
 */
protected static int decodeSingle(final byte[] encoded, final int offset) {

    if (encoded == null) {
        throw new IllegalArgumentException("null encoded");
    }

    if (encoded.length < 2) {
        // not required
        throw new IllegalArgumentException(
            "encoded.length(" + encoded.length + ") < 2");
    }

    if (offset < 0) {
        throw new IllegalArgumentException("offset(" + offset + ") < 0");
    }

    if (offset >= encoded.length - 1) {
        throw new IllegalArgumentException(
            "offset(" + offset + ") >= encoded.length(" + encoded.length
            + ") - 1");
    }

    return (decodeHalf(encoded[offset]) << 4)
           | decodeHalf(encoded[offset + 1]);
}


/**
 * Encodes given sequence of nibbles into a sequence of octets.
 *
 * @param encoded the nibbles to decode.
 *
 * @return the encoded octets.
 */
protected static byte[] decodeMultiple(final byte[] encoded) {

    if (encoded == null) {
        throw new IllegalArgumentException("null encoded");
    }

    if ((encoded.length & 0x01) == 0x01) {
        throw new IllegalArgumentException(
            "encoded.length(" + encoded.length + ") is not even");
    }

    final byte[] decoded = new byte[encoded.length >> 1];

    int offset = 0;
    for (int i = 0; i < decoded.length; i++) {
        decoded[i] = (byte) decodeSingle(encoded, offset);
        offset += 2;
    }

    return decoded;
}


/**
 * Decodes given sequence of nibbles into a sequence of octets.
 *
 * @param encoded the nibbles to decode.
 *
 * @return the decoded octets.
 */
public byte[] decode(final byte[] encoded) {

    return decodeMultiple(encoded);
}

1

Bu çok hızlı bir yol. Harici libaries gerekmez.

final protected static char[] HEXARRAY = "0123456789abcdef".toCharArray();

    public static String encodeHexString( 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] = HEXARRAY[v >>> 4];
            hexChars[j * 2 + 1] = HEXARRAY[v & 0x0F];
        }
        return new String(hexChars);
    }

1

Bayt String ile tam olarak ne demek istediğinizi anlayamıyordum, ancak bayttan String'e bazı dönüşümler var ve tam tersi, elbette resmi belgelerde çok daha fazlası var

Integer intValue = 149;

Karşılık gelen bayt değeri:

Byte byteValue = intValue.byteValue(); // this will convert the rightmost byte of the intValue to byte, because Byte is an 8 bit object and Integer is at least 16 bit, and it will give you a signed number in this case -107

tam sayı değerini bir Bayt değişkeninden geri alır:

Integer anInt = byteValue.intValue(); // This will convert the byteValue variable to a signed Integer

Byte ve Integer dan hex Dize:
Ben bunu yapmanın yolu:

Integer anInt = 149
Byte aByte = anInt.byteValue();

String hexFromInt = "".format("0x%x", anInt); // This will output 0x95
String hexFromByte = "".format("0x%x", aByte); // This will output 0x95

Bayt dizisini onaltılı bir dizeye dönüştürme:
Bildiğim kadarıyla, bir dizinin içindeki tüm Objectöğeleri başka bir öğeye dönüştürmek için basit bir işlev yoktur Object, Bu yüzden bunu kendiniz yapmanız gerekir. Aşağıdaki işlevleri kullanabilirsiniz:

Byte [] 'dan String'e:

    public static String byteArrayToHexString(byte[] byteArray){
        String hexString = "";

        for(int i = 0; i < byteArray.length; i++){
            String thisByte = "".format("%x", byteArray[i]);
            hexString += thisByte;
        }

        return hexString;
    }

Ve onaltılık dizeden bayta []:

public static byte[] hexStringToByteArray(String hexString){
    byte[] bytes = new byte[hexString.length() / 2];

    for(int i = 0; i < hexString.length(); i += 2){
        String sub = hexString.substring(i, i + 2);
        Integer intVal = Integer.parseInt(sub, 16);
        bytes[i / 2] = intVal.byteValue();
        String hex = "".format("0x%x", bytes[i / 2]);
    }

    return bytes;
}  

Çok geç ama umarım bu bazılarına yardımcı olabilir;)


1

Hızlı yönteminiz var:

    private static final String[] hexes = 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 hexes[b&0xFF];
    }

1
çirkin, ama muhtemelen çok verimli. :-)
Zengin S

1

Diğer bazı cevaplar gibi, String.format()ve de kullanmanızı öneririm BigInteger. Ancak bayt dizisini ikinin tamamlayıcı ikili temsili yerine büyük endian ikili temsili olarak yorumlamak için (signum ve olası onaltılık değerler aralığının eksik kullanımı ile) BigInteger (int signum, byte [] büyüklüğü) kullanın , BigInteger (bayt [] val değil ) kullanın ) .

Örneğin, 8 uzunluklu bir bayt dizisi için şunu kullanın:

String.format("%016X", new BigInteger(1,bytes))

Avantajları:

  • baştaki sıfırlar
  • imza yok
  • sadece yerleşik işlevler
  • sadece bir satır kod

dezavantajı:

  • bunu yapmanın daha etkili yolları olabilir

Misal:

byte[] bytes = new byte[8];
Random r = new Random();
System.out.println("big-endian       | two's-complement");
System.out.println("-----------------|-----------------");
for (int i = 0; i < 10; i++) {
    r.nextBytes(bytes);
    System.out.print(String.format("%016X", new BigInteger(1,bytes)));
    System.out.print(" | ");
    System.out.print(String.format("%016X", new BigInteger(bytes)));
    System.out.println();
}

Örnek çıktı:

big-endian       | two's-complement
-----------------|-----------------
3971B56BC7C80590 | 3971B56BC7C80590
64D3C133C86CCBDC | 64D3C133C86CCBDC
B232EFD5BC40FA61 | -4DCD102A43BF059F
CD350CC7DF7C9731 | -32CAF338208368CF
82CDC9ECC1BC8EED | -7D3236133E437113
F438C8C34911A7F5 | -BC7373CB6EE580B
5E99738BE6ACE798 | 5E99738BE6ACE798
A565FE5CE43AA8DD | -5A9A01A31BC55723
032EBA783D2E9A9F | 032EBA783D2E9A9F
8FDAA07263217ABA | -70255F8D9CDE8546

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.