Javaコードバイトを16進数に変換するには


184

バイトの配列があります。その配列の各バイト文字列を対応する16進値に変換する必要があります。

バイト配列を16進数に変換するJavaの関数はありますか?


2
Javaでバイト配列と呼ぶものは、他の言語ではバイト文字列と呼ばれます(例:docs.racket-lang.org/guide/bytestrings.html
Patrick Favre

回答:


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 "

こちらもご覧ください

  • java.util.Formatter 構文
    • %[flags][width]conversion
      • フラグ'0'-結果にはゼロが埋め込まれます
      • 2
      • 変換'X'-結果は大文字の16進整数としてフォーマットされます

質問のテキストを見ると、これが要求されているものである可能性もあります。

    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]"

ここでいくつかの答えは使用しInteger.toHexString(int)ます。これは可能ですが、いくつかの注意点があります。パラメータはであるため、符号拡張を含む引数intに対して拡大プリミティブ変換が実行されbyteます。

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

byteJavaで署名された8ビットは、32ビットに符号拡張されますint。この符号拡張を効果的に元に戻すには、bytewithでマスクでき0xFFます。

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

使用に関するもう1つの問題toHexStringは、ゼロが埋め込まれないことです。

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

両方の要素を組み合わせると、String.formatソリューションがより優先されます。

参考文献


@Vivek:「非常に大きな値」とは何ですか?入力と出力は何ですか?
polygenelubricants

もう一度説明しましょう。配列にバイト文字列のコレクションがあります。しかし、私がしなければならないのは、各バイトを個別に分析することです。したがって、配列全体ではなく、個々のバイト文字列を一度に処理する必要はありません。これは、その配列の1つのコンポーネントです。.「アレイ"。次のコードでは、「byte bv = 10; String hexString = Integer.toHexString(bv);」CAse 1(Byte Recieved:68 Hex Output::44)Case:2(Byte Recieved:-46 Hex Output::ffffffd2) .........一部の値でこのような予期しない結果が出るのはなぜですか?
-Vivek

1
@Vivek:の使用に関する私の答えを読んでくださいtoHexString& 0xFFつまり、でマスクする必要Integer.toHexString(-46 & 0xFF)があり"d2"ます。
polygenelubricants

@polygenelubricants:どうもありがとう..ようやく、コードは正常に動作しているようです。今すぐtoHexString関数を使用しても安全ですか?または、アプローチに抜け穴があるかもしれませんか?
Vivek

1
@Vivek:「安全」です。注意して、byte値を& 0xFF毎回マスクする必要があります。format上記のソリューションでは、引数として実際に使用しているものに応じてマスキングが必要になる場合もあります。
polygenelubricants

65

既存の回答のどれも彼らのアプローチが機能しない理由を説明していないため、私が投稿しています。これは、この問題にとって本当に重要だと思います。これにより、提案されたソリューションが不必要に複雑で微妙に見える場合があります。説明するためにかなり簡単なアプローチを提供しますが、それが機能する理由を説明するのに役立つように、もう少し詳しく説明します。

まず、何をしようとしていますか?バイト値(またはバイトの配列)を、ASCIIで16進値を表す文字列に変換したいとします。したがって、ステップ1は、Javaのバイトが何であるかを正確に調べることです。

バイトデータ型は、8ビットの符号付き2の補数の整数です。最小値は-128、最大値は127(両端を含む)です。バイトデータ型は、メモリの節約が実際に重要である大きな配列でメモリを節約するのに役立ちます。また、intの代わりに使用して、制限がコードを明確にするのに役立ちます。変数の範囲が制限されているという事実は、ドキュメントの形式として役立ちます。

これは何を意味するのでしょうか?いくつかのこと:最初にそして最も重要なことは、8ビットで作業していることを意味します。たとえば、2を0000 0010と書くことができます。ただし、2の補数なので、次のように負の2を書きます:11111110。また、16進数への変換は非常に簡単です。つまり、各4ビットセグメントを16進数に直接変換するだけです。このスキームで負の数を理解するには、まず2の補数を理解する必要があることに注意してください。2の補数をまだ理解していない場合は、優れた説明をここで読むことができます。http//www.cs.cornell.edu/~tomf/notes/cps104/twoscomp.html


一般に2の補数を16進数に変換する

数値が2の補数になると、16進数に変換するのは簡単です。一般に、バイナリから16進数への変換は非常に簡単です。次の2つの例でわかるように、2の補数から16進数に直接移動できます。

例1: 2を16進数に変換します。

1)最初に2を2の補数でバイナリに変換します。

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

2)バイナリを16進数に変換します。

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

therefore 2 = 0000 0010 = 0x02. 

例2: -2(2の補数)を16進数に変換します。

1)最初に-2を2の補数でバイナリに変換します。

-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)16進数に変換します。

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

therefore: -2 = 1111 1110 = 0xFE.


Javaでこれを行う

これでコンセプトをカバーできたので、簡単なマスキングとシフトで目的を達成できることがわかります。理解しておくべき重要なことは、変換しようとしいるバイトがすでに2の補数であることです。この変換を自分で行うことはありません。これがこの問題の大きな混乱点だと思います。次のバイト配列を例にとります。

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

上記のように手動で16進数に変換しましたが、Javaでどのように実行できますか?方法は次のとおりです。

ステップ1:計算を保持するStringBufferを作成します。

StringBuffer buffer = new StringBuffer();

ステップ2:上位ビットを分離し、それらを16進数に変換して、バッファーに追加する

2進数1111 1110を指定すると、上位ビットを最初に4だけシフトして分離し、次に残りの数をゼロにすることができます。論理的にはこれは簡単ですが、Java(および多くの言語)での実装の詳細では、符号拡張によりしわが生じます。基本的に、バイト値をシフトすると、Javaはまず値を整数に変換し、次に符号拡張を実行します。したがって、1111 1110 >> 4は0000 1111であると予想されますが、実際には、Javaでは2の補数0xFFFFFFFFとして表されます。

したがって、例に戻ります。

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

次に、マスクを使用してビットを分離できます。

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

Javaでは、これをすべて一度に実行できます。

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

forDigit関数は、渡した数値を16進数の0〜Fのセットにマッピングするだけです。

ステップ3:次に、下位ビットを分離する必要があります。必要なビットは既に正しい位置にあるため、マスクするだけです。

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

以前と同様に、Javaではこれをすべて一度に実行できます。

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

これをすべてまとめると、forループとして実行して配列全体を変換できます。

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));
}

うまくいけば、この説明によって、インターネットで見つかる多くの例で何が起こっているのか正確に疑問に思う人たちにとって、物事がより明確になるでしょう。うまくいけば、重大なエラーは発生しませんでしたが、提案や修正は大歓迎です!


4
ベストアンサー!16進数の文字列からバイトへの対称的な実装では、変換を使用しますCharacter.digit()(byte) ((Character.digit(str.charAt(0), 16) << 4) + Character.digit(str.charAt(1), 16))
たとえば

21

最速の私はまだこれを行うために見つけた方法は以下の通りであります:

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();
}

それは〜よりも50倍高速ですString.format。テストしたい場合:

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
        }

    }
}

編集:ほんの少し速く、JRE 9と互換性のない何かを見つけました。自己責任で使用してください

import javax.xml.bind.DatatypeConverter;

DatatypeConverter.printHexBinary(raw);

2
DatatypeConverterは、Java 9で使用できなくなっ危険なことは、それは、Java 1.8またはそれ以前(それ以前に元の設定でJava 9)の下でコンパイルしますが、Java 9の下で、実行時例外が発生します使用してコードではありません
スティーブン・M -on strike-

@StephenMsポイントの2番目:jre9でこれを使用するとClassNotFound例外でクラッシュします
Patrick Favre

実際にはprintHexBinary 、jdkのsrc.zipからソースコードメソッドを単純に抽出できます 。これは、1番目のメソッドよりも1倍速いようです。
Fruit

1
HEXES定数の文字配列を使用する場合、代わりにStringとcharAt()を使用すると、速度が最大20%向上します。
Dyorgio

15

この方法を試してください:

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

配列の扱い(私があなたを正しく理解していれば):

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();

polygenelubricantsが述べたように、それString.format()Integer.toHexString()(負の数を正しい方法で処理するため)と比較して正しい答えです。


2
これは拡張に署名し-1ます。
ポリジェネ

バイトbv = 10; 文字列hexString = Integer.toHexString(bv); これはうまく機能するようです..配列のすべての要素に個別に適用できます..他のコード(配列の扱い)は、大きすぎる値を返します。その理由は何でしょうか?
のVivek

@Vivek、bvこれは単一の16進文字を返すためです。一方、残りのコードは16進文字の文字列を返します。コードをデリミタで変更したので、理解できるようになりました。
0x2D9A3

@Bar:with をInteger.toHexStringマスクしbyte0xFF符号拡張を元に戻す場合でも使用できます。
polygenelubricants

CAse 1(Byte Recieved:68 Hex Output::44)Case:2(Byte Recieved:-46 Hex Output::ffffffd2)負のバイト配列の場合、予期しない出力値を取得しています...これの処理方法は?
のVivek

13

最良の解決策は、このひどいワンライナーです:

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

ここで述べたよう


4
DatatypeConverterは、Java 9で使用できなくなっ危険なことは、それは、Java 1.8またはそれ以前(それ以前に元の設定でJava 9)の下でコンパイルしますが、Java 9の下で、実行時例外が発生します使用してコードではありません
スティーブン・M -on strike-

jdk9にないと言って悲しい。new BigInteger(byteArray).toString(16)次に行く方法です。パフォーマンスの問題はありますか?
prayagupd 2017年

パフォーマンスの問題ではないかもしれませんが、先行ゼロが
欠落します(

それはまだJava 9ドキュメントにあるように見えるので、私が言えることからそれをまだ使用しても問題ないようです
Brad Parks

ここで説明するように、java9で使用しても問題ありませんが、将来のJavaリリースでは削除される予定です。また、バージョン2.3.0以降の「新しい」スタンドアロンjaxbモジュールでも引き続き使用できます。
lynx

11

バイトを明確に回復できるように、つまりの0A代わりにA、一定幅の16進表記が必要な場合は、以下を試してくださいformat()

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

11

を使用byte[]して16進文字列に変換する短くて簡単な方法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

使い方?

組み込みシステムクラスjava.math.BigIntegerクラス(java.math.BigInteger)は、バイナリおよび16進データと互換性があります。

  • その最初のパラメーターを設定することBigInteger(signum=1, byte[])により、大きな整数を作成するコンストラクターがありbyte[]ますsignum=1負のバイトを正しく処理します)
  • BigInteger.toString(16)大きな整数を16進数に変換するために使用します文字列ます
  • 16進数を解析するにnew BigInteger("ffa74b", 16)は、先頭の0を正しく処理しません

16進数の結果に先行ゼロを含める場合は、そのサイズを確認し、必要に応じて欠落しているゼロを追加します。

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

ノート

new BigInteger(1, bytes)代わりにを使用してくださいnew BigInteger(bytes)。Javaは「設計上byte無効」であり、データ型はバイトを保持せず、符号付きの小さな整数[-128 ... 127]を保持するためです。最初のバイトが負の場合、BigIntegerは負の大整数を渡すと想定します。1最初のパラメーター(signum=1)として渡すだけです。

16進数からへbyte[]の変換はトリッキーです。生成された出力に先行ゼロが入る場合があるため、次のようにクリーンアップする必要があります。

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;
}

最後の注意点は、にbyte[]いくつかの先行ゼロがある場合、それらは失われます。


1
先頭バイトに16未満の10進値がある場合は、奇数の16進文字の文字列も取得されます。
Alex Jorgenson、

8

外部ライブラリを使用してよろしければ、org.apache.commons.codec.binary.HexクラスにはencodeHexaを受け取ってbyte[]を返すメソッドがありますchar[]。この方法は、フォーマットオプションよりもはるかに高速で、変換の詳細をカプセル化します。またdecodeHex、逆の変換のためのメソッドが付属しています。


4
さらに簡単な方法は、組み込み関数javax.xml.bind.DatatypeConverter / parseHexBinaryおよびprintHexBinaryを使用することです。stackoverflow.com/questions/9655181/…を
アラントンプソン

2
このオプションに+1します。Hexには、byte []を取得してStringを返すメソッドencodeHexStringもあります。
明江市2015

javax名前空間が常に利用できるとは限らないことを忘れないでください。
Mene 2016年

7

Bouncy Castle Providerライブラリのメソッドを使用できます。

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

Bouncy Castle Cryptoパッケージは、暗号化アルゴリズムのJava実装です。このjarには、JDK 1.5からJDK 1.8のBouncy Castle Cryptography APIのJCEプロバイダーと軽量APIが含まれています。

Maven依存関係:

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

またはApache Commons Codecから:

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

Apache Commons Codecパッケージには、Base64や16進数などのさまざまなフォーマット用のシンプルなエンコーダーとデコーダーが含まれています。これらの広く使用されているエンコーダーとデコーダーに加えて、コーデックパッケージは音声エンコーディングユーティリティのコレクションも維持します。

Maven依存関係:

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

はい、これが最良のソリューションですが、外部ライブラリが必要です:Apache Commons Codecmvnrepository.com/artifact/commons-codec/commons-codec/1.11)またはBouncyCastle Providermvnrepository.com/artifact/org.bouncycastle/bcprov- jdk15on / 1.60
Svetlin Nakov

5

これは、これまでで最も速く実行できることがわかったコードです。23msで、長さ32の109015バイト配列で実行しました。私はそれをVM上で実行していたため、おそらくベアメタル上でより高速に実行されます。

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;
}

その後、あなたはただ行うことができます

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

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

機能しません:BigInteger(byteArrayOf(-1, 2, 3, 4, 5)).toString(16)リターン"-fdfcfbfb"
Martin Vysny

それは正しい結果です。バイト '-1'、 '2' ... '5'で作業しています。そのバイトには視覚化(unicode.org)がありません。リテラル '-1'、 '2' ... '5'を使用する場合は、文字列値を使用する必要があります。
ヴェンダー

それは間違った結果です。Javaバイト(int) 255は署名されているため、-1のJavaバイト値は実際には0xFF(と同じです)なので、結果はになりますFF02030405。上記の@Jerinawソリューションを試してみると、正しい出力が印刷されることがわかります。以下のSvetlin Nakovのソリューションも参照してください。
マーティンヴィスニー

2

これは、バイトを16進数に変換する単純な関数です

   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

その他は一般的なケースをカバーしています。しかし、MACアドレスなどの既知の形式のバイト配列がある場合は、次のことができます。

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

の束を作成(および破壊) Stringパフォーマンスが問題になる場合インスタンスは良い方法ではありません。

これらの冗長(重複)引数チェックステートメント(ifs)は無視してください。それは(別の)教育目的のためです。

完全なmavenプロジェクト:http : //jinahya.googlecode.com/svn/trunk/com.googlecode.jinahya/hex-codec/

エンコーディング...

/**
 * 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);
}

デコードしています...

/**
 * 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

これは非常に速い方法です。外部ライブラリは必要ありません。

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

私はあなたがバイト文字列によって正確に何を意味しているのか理解できませんでしたが、ここではバイトから文字列への変換とその逆の変換をいくつか示します。もちろん、公式のドキュメントにはもっとたくさんあります

Integer intValue = 149;

対応するバイト値は次のとおりです。

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

Byte変数から整数値を取得します。

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

バイトと整数から16進文字列へ:
これは私がやる方法です:

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

バイトの配列を16進文字列に変換する:
私が知る限り、いくつかの配列内のすべてのObject要素を別の要素に変換する単純な関数はないObjectので、自分で行う必要があります。次の関数を使用できます。

byte []からStringへ:

    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;
    }

そして16進文字列からbyte []へ:

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;
}  

手遅れですが、これが他の人に役立つことを願っています;)


1

あなたの速い方法があります:

    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
醜いですが、おそらく非常に効率的です。:-)
リッチS

1

ただ、いくつかの他の回答のように、私が使用することをお勧めしますString.format()BigInteger。ただし、バイト配列を2の補数のバイナリ表現なくビッグエンディアンのバイナリ表現として解釈するに(可能な16進値の範囲の符号と不完全な使用でBigInteger(byte [] valではなくBigInteger(int signum、byte [] itude)を使用します。 )

たとえば、長さが8のバイト配列の場合は、次のように使用します。

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

利点:

  • 先行ゼロ
  • サインなし
  • 組み込み関数のみ
  • コードは1行だけ

不利益:

  • それを行うためのより効率的な方法があるかもしれません

例:

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();
}

出力例:

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.