Longをbyte []に​​変換してJavaに戻す方法


159

Javaでa longをa に変換してbyte[]戻す方法を教えてください。

TCP接続経由で送信できるようにa longをaに変換しようとしています。反対側では、それを取得してに戻したいと思います。byte[]byte[]byte[]double


別の代替手段は、コレクションを変換するための一般的なツールであるMaps.transformValuesです。docs.guava-libraries.googlecode.com/git-history/release/javadoc/...
ラウル

1
longを最少数のBase64文字に変換することを目標とする場合は、stackoverflow.com / q / 27559449/32453も参照してください。
rogerdpack 2016年

おそらく、変換パイプラインは「long-> byte []-> long-> double」ではなく、「long-> byte []-> double」であることを強調する必要があります。
Kirill Gamazkov 2017年

回答:


230
public byte[] longToBytes(long x) {
    ByteBuffer buffer = ByteBuffer.allocate(Long.BYTES);
    buffer.putLong(x);
    return buffer.array();
}

public long bytesToLong(byte[] bytes) {
    ByteBuffer buffer = ByteBuffer.allocate(Long.BYTES);
    buffer.put(bytes);
    buffer.flip();//need flip 
    return buffer.getLong();
}

または、ByteBufferの繰り返し作成を回避するためにクラスにラップされます。

public class ByteUtils {
    private static ByteBuffer buffer = ByteBuffer.allocate(Long.BYTES);    

    public static byte[] longToBytes(long x) {
        buffer.putLong(0, x);
        return buffer.array();
    }

    public static long bytesToLong(byte[] bytes) {
        buffer.put(bytes, 0, bytes.length);
        buffer.flip();//need flip 
        return buffer.getLong();
    }
}

これは非常に人気が高まっているので、ほとんどの場合、Guavaのようなライブラリを使用したほうがいいと思います。ライブラリに奇妙な反対がある場合は、ネイティブJavaソリューションの場合は、おそらく最初にこの答えを検討する必要があります。私の答えは、システムのエンディアンについて自分で心配する必要がないということです。


3
賢い...しかし、変換ごとに一時的なByteBufferを作成して破棄します。メッセージごとに複数のlongを送信している場合や、多数のメッセージを送信している場合は適切ではありません。
スティーブンC

1
@Stephen-ByteBufferの使用方法を示すのに十分なだけでしたが、先に進み、ユーティリティクラスでの使用例を追加しました。
Brad Mace、

8
putsの後の位置がバッファの最初ではなく最後にあるため、ここでのbytesToLong()は失敗すると思います。バッファアンダーフロー例外が発生すると思います。
Alex Miller

11
Java 8より前のバージョンでは、マジックナンバーを回避するために、Long.BYTESの代わりにLong.SIZE / Byte.SIZEを使用できます。
jvdbogae 14

8
そのバイトバッファの再利用は非常に問題が多く、スレッドセーフの理由だけでなく他の人もコメントしています。その間に '.clear()'が必要になるだけでなく、ByteBufferで.array()を呼び出すと、コピーではなくバッキング配列が返されることは明らかではありません。したがって、繰り返し呼び出して他の結果を保持する場合、それらは実際にはすべて同じ配列であり、以前の値を繰り返し上書きしています。以下のコメントのhadoopリンクは最もパフォーマンスが高く、これらの問題を回避します。
アーロンジンマン2014年


84

ByteBufferメソッドを単純なビット単位の操作に対してテストしましたが、後者は大幅に高速です。

public static byte[] longToBytes(long l) {
    byte[] result = new byte[8];
    for (int i = 7; i >= 0; i--) {
        result[i] = (byte)(l & 0xFF);
        l >>= 8;
    }
    return result;
}

public static long bytesToLong(final byte[] bytes, final int offset) {
    long result = 0;
    for (int i = offset; i < Long.BYTES + offset; i++) {
        result <<= Long.BYTES;
        result |= (bytes[i] & 0xFF);
    }
    return result;
}

1
結果の代わりに| =(b [i]&0xFF); 結果を使用することができます| = b [i]; 少し0xFFとして、何も変更しません。
Vipul

3
@Vipul bitwise-andは重要です。なぜならresult |= b[i]、バイト値だけを実行する場合、最初に符号拡張を行うlongに最初に変換されるためです。値が-128(16進数0x80)のバイトは、値が-128(16進数)のlongに変わり0xFFFF FFFF FFFF FF80ます。最初に変換後の値は、or:edされます。bitwise-andを使用すると、最初にバイトをintに変換し、符号拡張を切り離すことでこれを防止します(byte)0x80 & 0xFF ==> (int)0xFFFF FF80 & 0xFF ==> (int) 0x80。なぜバイトがJavaで署名されるのか私には少し不思議ですが、それは他の型に合わせる必要があると思います。
ブレーンストーミング

@Brainstorm | = b [i]と| =(b [i]&0xFF)でケース-128を試しましたが、結果は同じです!!
Mahmoud Hanafy 2016

問題は、シフトが適用される前にバイトが昇格され、符号ビットに奇妙な問題が発生することです。したがって、最初に(&)0xFFを使用して、シフトする正しい値を取得します。
Wytze、2016

このデータ(data = new byte [] {(byte)0xDB、(byte)0xA7、0x53、(byte)0xF8、(byte)0xA8、0x0C、0x66、0x8};)をlongに変換しようとしましたが、それは返されますfalse値-2619032330856274424、期待値は989231983928329832
jefryジャッキー

29

高速のアンロールバージョンを探している場合は、長さが8の「b」というバイト配列を想定して、これでうまくいくはずです。

byte []-> long

long l = ((long) b[7] << 56)
       | ((long) b[6] & 0xff) << 48
       | ((long) b[5] & 0xff) << 40
       | ((long) b[4] & 0xff) << 32
       | ((long) b[3] & 0xff) << 24
       | ((long) b[2] & 0xff) << 16
       | ((long) b[1] & 0xff) << 8
       | ((long) b[0] & 0xff);

上記と完全に対応するlong- > byte []

byte[] b = new byte[] {
       (byte) lng,
       (byte) (lng >> 8),
       (byte) (lng >> 16),
       (byte) (lng >> 24),
       (byte) (lng >> 32),
       (byte) (lng >> 40),
       (byte) (lng >> 48),
       (byte) (lng >> 56)};

1
ありがとう、最高!
Miha_x64

15

なぜbyte []が必要なのですか?なぜそれをソケットに書き込むのではないのですか?

Longではなくlongを意味すると思いますが、後者はnull値を許可する必要があります。

DataOutputStream dos = new DataOutputStream(
     new BufferedOutputStream(socket.getOutputStream()));
dos.writeLong(longValue);

DataInputStream dis = new DataInputStream(
     new BufferedInputStream(socket.getInputStream()));
long longValue = dis.readLong();

8
彼は、byte []に​​変換する方法と戻す方法を尋ねました。良い答えですが、質問には答えませんでした。それは不必要だと思うので理由を尋ねますが、それは間違った仮定です。彼がクロスランゲージまたはクロスプラットフォームをしている場合はどうなりますか?DataOutputStreamはそこでは役に立ちません。
user1132959 2013年

4
彼がクロスランゲージまたはクロスプラットフォームを実行している場合、既知の順序でバイトを送信することが重要です。このメソッドは、ドキュメントに従ってそれを実行します(「上位バイトが先に」書き込まれます)。受け入れられた答えはしません(ドキュメントによると、「現在の順序」でそれらを書き込みます)。質問は、彼がそれらをTCP接続を介して送信したいと述べています。これbyte[]はそのための手段にすぎません。
Ian McLaird 2013

3
@IanMcLaird受け入れられた回答は既知の順序を使用しています。これは、新しいを作成するByteBufferドキュメントに応じた「バイトバッファの初期順序は、常にBIG_ENDIANです。
デビッド・フィリップス

4

基になるByteArrayOutputStreamでDataOutputStreamに longを書き込むだけです。ByteArrayOutputStreamから、toByteArray()を介してバイト配列を取得できます。

class Main
{

        public static byte[] long2byte(long l) throws IOException
        {
        ByteArrayOutputStream baos=new ByteArrayOutputStream(Long.SIZE/8);
        DataOutputStream dos=new DataOutputStream(baos);
        dos.writeLong(l);
        byte[] result=baos.toByteArray();
        dos.close();    
        return result;
        }


        public static long byte2long(byte[] b) throws IOException
        {
        ByteArrayInputStream baos=new ByteArrayInputStream(b);
        DataInputStream dos=new DataInputStream(baos);
        long result=dos.readLong();
        dos.close();
        return result;
        }


        public static void main (String[] args) throws java.lang.Exception
        {

         long l=123456L;
         byte[] b=long2byte(l);
         System.out.println(l+": "+byte2long(b));       
        }
}

それに応じて他のプリミティブでも機能します。

ヒント:TCPの場合、手動でbyte []は必要ありません。ソケット socketとそのストリームを使用します

OutputStream os=socket.getOutputStream(); 
DataOutputStream dos=new DataOutputStream(os);
dos.writeLong(l);
//etc ..

代わりに。


4

org.apache.hadoop.hbase.util.Bytes http://hbase.apache.org/apidocs/org/apache/hadoop/hbase/util/Bytes.htmlの実装を使用できます。

ソースコードはここにあります:

http://grepcode.com/file/repository.cloudera.com/content/repositories/releases/com.cloudera.hbase/hbase/0.89.20100924-28/org/apache/hadoop/hbase/util/Bytes.java# Bytes.toBytes%28long%29

toLongメソッドとtoBytesメソッドを探します。

ソフトウェアライセンスではコードの一部を取得して使用できると思いますが、それを確認してください。


なぜその実装はORではなくXOR(^ =)を使用するのですか? github.com/apache/hbase/blob/master/hbase-common/src/main/java/...
victtim

3
 public static long bytesToLong(byte[] bytes) {
        if (bytes.length > 8) {
            throw new IllegalMethodParameterException("byte should not be more than 8 bytes");

        }
        long r = 0;
        for (int i = 0; i < bytes.length; i++) {
            r = r << 8;
            r += bytes[i];
        }

        return r;
    }



public static byte[] longToBytes(long l) {
        ArrayList<Byte> bytes = new ArrayList<Byte>();
        while (l != 0) {
            bytes.add((byte) (l % (0xff + 1)));
            l = l >> 8;
        }
        byte[] bytesp = new byte[bytes.size()];
        for (int i = bytes.size() - 1, j = 0; i >= 0; i--, j++) {
            bytesp[j] = bytes.get(i);
        }
        return bytesp;
    }

2
ArrayListはスキップできます。public static byte [] longToBytes(long l){long num = l; バイト[]バイト=新しいバイト[8]; for(int i = bytes.length-1、i> = 0; i--){bytes [i] =(byte)(num&0xff); num >> = 8; } bytespを返します。}
eckes

元のメソッドは、while(l!= 0)で無限ループになるため、負の数では機能しません。@ eckesのメソッドは、127を超えるバイト数が負になることを考慮していないため、127を超える数では機能しません。彼らは署名されています。
Big_Bad_E

2

私は可能な限り最速の別の回答を追加しますye(はい、受け入れられた回答よりもさらに多いです)が、すべてのケースで機能するわけではありません。ただし、考えられるすべてのシナリオで機能します。

Stringを中間として使用できます。「通常」の文字列で作業していることを知っている限り、文字列を使用すると誤った結果が生じる可能性があるように見えても、これにより正しい結果が得られます。これは有効性を高め、コードをより単純にする方法であり、操作するデータ文字列に対していくつかの仮定を使用する必要があります。

この方法の欠点:場合の欠点 ASCIIテーブルの先頭でこれらの記号のようないくつかのASCII文字場合、次の行は失敗する可能性がありますが、それに直面しましょう。

この方法を使用するプロ:ほとんどの人は通常、異常な文字を含まない通常の文字列で作業します。その場合、この方法が最も簡単で最速の方法です。

Longからbyte []へ:

byte[] arr = String.valueOf(longVar).getBytes();

byte []からLongへ:

long longVar = Long.valueOf(new String(byteArr)).longValue();

2
ネクロポスティングして申し訳ありませんが、それは間違っています。例:String.valueOf(0).getBytes()[0] == 0x30。驚き!String#getBytesは、数字ではなくASCIIエンコードされた数字記号を返します: '0'!= 0ですが、 '0' == 0x30
Kirill Gamazkov

あなたは私の全体の答えを読んでいた場合はまあ、多分、あなたは..私は答えそのもので、それについて警告している見たのだ
Yonatanニール

1
ああ、中間のbyte []データが(ほとんど)不透明なものとして扱われるという点を逃しました。あなたのトリックはこのシナリオのために行います。
Kirill Gamazkov 2017年

1

OutputStreamソケットへの書き込みに既にを使用している場合は、DataOutputStreamが適しています。次に例を示します。

// Assumes you are currently working with a SocketOutputStream.

SocketOutputStream outputStream = ...
long longValue = ...

DataOutputStream dataOutputStream = new DataOutputStream(outputStream);

dataOutputStream.writeLong(longValue);
dataOutputStream.flush();

同様の方法がありshortintfloatあなたがそれから使用することができ、などのDataInputStreamを受信側では。



0

Java 8以降byte[]long使用するように変換する別の方法を次に示します。

private static int bytesToInt(final byte[] bytes, final int offset) {
    assert offset + Integer.BYTES <= bytes.length;

    return (bytes[offset + Integer.BYTES - 1] & 0xFF) |
            (bytes[offset + Integer.BYTES - 2] & 0xFF) << Byte.SIZE |
            (bytes[offset + Integer.BYTES - 3] & 0xFF) << Byte.SIZE * 2 |
            (bytes[offset + Integer.BYTES - 4] & 0xFF) << Byte.SIZE * 3;
}

private static long bytesToLong(final byte[] bytes, final int offset) {
    return toUnsignedLong(bytesToInt(bytes, offset)) << Integer.SIZE |
            toUnsignedLong(bytesToInt(bytes, offset + Integer.BYTES));
}

aの変換はlong、ビット単位のORの対象となる2つの整数値の上位ビットと下位ビットとして表すことができます。toUnsignedLongIntegerクラスからのものであり、最初の呼び出しtoUnsignedLongは不要な場合があることに注意してください。

他の人が述べたように、逆の変換も展開できます。


0

LongおよびByteArrayタイプのKotlin拡張機能:

fun Long.toByteArray() = numberToByteArray(Long.SIZE_BYTES) { putLong(this@toByteArray) }

private inline fun numberToByteArray(size: Int, bufferFun: ByteBuffer.() -> ByteBuffer): ByteArray =
    ByteBuffer.allocate(size).bufferFun().array()

@Throws(NumberFormatException::class)
fun ByteArray.toLong(): Long = toNumeric(Long.SIZE_BYTES) { long }

@Throws(NumberFormatException::class)
private inline fun <reified T: Number> ByteArray.toNumeric(size: Int, bufferFun: ByteBuffer.() -> T): T {
    if (this.size != size) throw NumberFormatException("${T::class.java.simpleName} value must contains $size bytes")

    return ByteBuffer.wrap(this).bufferFun()
}

私のライブラリhttps://github.com/ArtemBotnev/low-level-extensionsで完全なコードを見ることができます

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