Java에서 Long을 byte []로 변환하고 다시 변환하는 방법


159

Java에서 a long를 a 로 변환하고 어떻게 byte[]다시 변환 합니까?

TCP 연결을 통해 보낼 수 있도록 a long를 로 변환하려고 합니다. 다른 쪽에서는 그것을 가져 와서 다시로 변환 하고 싶습니다 .byte[]byte[]byte[]double


또 다른 대안은 컬렉션을 변환하는 일반적인 도구 인 Maps.transformValues입니다. docs.guava-libraries.googlecode.com/git-history/release/javadoc/…
Raul

1
long을 가장 적은 수의 Base64 문자로 변환하는 것이 목표라면 stackoverflow.com/q/27559449/32453을 참조하십시오 .
rogerdpack

변환 파이프 라인이 'long-> byte []-> long-> double'이 아니라 'long-> byte []-> double'임을 강조해야합니다.
Kirill Gamazkov

답변:


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

이것이 인기가 있기 때문에 대다수의 경우 구아바와 같은 라이브러리를 사용하는 것이 더 좋다고 생각합니다. 그리고 라이브러리에 대한 이상한 반대가 있다면 네이티브 Java 솔루션에 대해이 답변을 먼저 고려해야 합니다 . 내 대답은 실제로 시스템의 엔디안 자체에 대해 걱정할 필요가 없다는 것입니다.


3
영리한 ...하지만 각 변환에 대해 임시 ByteBuffer를 만들어 버립니다. 메시지 및 / 또는 많은 메시지 당 여러 개의 long을 보내는 경우 좋지 않습니다.
Stephen C

1
@Stephen-ByteBuffer 사용법을 설명하기에 충분했지만 유틸리티 클래스에서 사용하는 예제를 추가했습니다.
Brad Mace

8
여기에서 bytesToLong ()은 put 이후의 위치가 시작이 아닌 버퍼의 끝에 있기 때문에 실패한다고 생각합니다. 버퍼 언더 플로 예외가 발생한다고 생각합니다.
Alex Miller

11
Java 8 이전에서는 Long.BYTES 대신 Long.SIZE / Byte.SIZE를 사용하여 마법 번호를 피할 수 있습니다.
jvdbogae

8
그 바이트 버퍼의 재사용은 다른 사람들이 언급 한 것처럼 스레드 안전성 이유로 인해 문제가되지 않습니다. 사이에 '.clear ()'가 필요할뿐만 아니라 ByteBuffer에서 .array ()를 호출하면 백업 배열과 복사본을 반환한다는 것이 분명하지 않습니다. 따라서 반복적으로 호출하고 다른 결과를 유지하면 실제로는 이전 값을 반복해서 덮어 쓰는 것과 동일한 배열입니다. 아래 주석의 hadoop 링크가 가장 성능이 우수하며 이러한 문제를 피합니다.
Aaron Zinman


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 result |= b[i]바이트 단위는 바이트 값만 long으로 변환되어 부호 확장을 나타 내기 때문에 비트 단위로 중요 합니다. 값이 -128 (hex 0x80) 인 바이트는 값이 -128 (hex ) 인 long으로 바뀝니다 0xFFFF FFFF FFFF FF80. 변환 후 첫 번째 값은 다음과 같습니다. 비트 단위를 사용하면 먼저 바이트를 int로 변환하고 부호 확장을 잘라서이를 방지합니다 (byte)0x80 & 0xFF ==> (int)0xFFFF FF80 & 0xFF ==> (int) 0x80. 바이트가 java로 서명 된 이유는 나에게 약간의 미스터리이지만 다른 유형과도 일치한다고 생각합니다.
Brainstorm

@Brainstorm 나는 | = b [i]와 | = (b [i] & 0xFF)로 case -128을 시도했으며 결과는 동일합니다 !!
Mahmoud Hanafy 2012

문제는 시프트가 적용되기 전에 바이트가 승격되어 부호 비트에 이상한 문제가 발생한다는 것입니다. 따라서 올바른 값을 이동하려면 먼저 0xFF로 (&)합니다.
Wytze

이 데이터 (data = new byte [] {(byte) 0xDB, (byte) 0xA7, 0x53, (byte) 0xF8, (byte) 0xA8, 0x0C, 0x66, 0x8};)를 long으로 변환하려고 시도하지만 반환합니다. 잘못된 값 -2619032330856274424, 예상 값은 989231983928329832
jefry jacky

29

빠른 롤링되지 않은 버전을 찾고 있다면 길이가 8 인 "b"라는 바이트 배열을 가정하여 트릭을 수행해야합니다.

바이트 []-> 긴

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

바이트 []가 왜 필요한가요? 왜 소켓에 쓰지 않습니까?

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

4
그가 언어 간 또는 플랫폼 간을 수행하는 경우 알려진 순서로 바이트를 보내는 것이 중요합니다. 이 방법은 문서에 따라이를 수행합니다 (먼저 "높은 바이트를 먼저 기록"). 수락 된 답변은 그렇지 않습니다 (문서에 따라 "현재 순서"로 씁니다). 이 질문은 TCP 연결을 통해 보내려고한다고 말합니다. 이는 byte[]그 목적을위한 수단 일뿐입니다.
Ian McLaird

3
@IanMcLaird 승인 된 답변은 알려진 순서를 사용합니다. 그것은 새로운 생성 ByteBuffer워드 프로세서에 따라하는 "byte 버퍼의 초기 순서는 항상 BIG_ENDIAN입니다.
데이비드 필립스에게

4

기본 ByteArrayOutputStream 을 사용하여 Long을 DataOutputStream에 작성하십시오 . 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# 바이트 / 바이트 % 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

원래의 방법은 무한 루프에있는 동안 음수와 함께 작동하지 않습니다 (l! = 0), @eckes의 방법은 127 이상의 음의 바이트를 고려하지 않기 때문에 127 이상의 숫자에서는 작동하지 않습니다 그들은 서명했다.
Big_Bad_E

2

나는 가능한 가장 빠른 ׂ (예, 허용 된 답변보다 더 많은) 인 또 다른 답변을 추가 할 것입니다. 그러나 모든 경우에 적용되지는 않습니다. 그러나 모든 가능한 시나리오에서 작동합니다.

단순히 문자열을 중간으로 사용할 수 있습니다. String을 사용하면 "NORMAL"문자열로 작업하고 있다는 것을 알면 오랫동안 잘못된 결과를 얻을 수있는 것처럼 보이지만 올바른 결과를 얻을 수 있습니다. 이것은 효과를 높이고 코드를 더 단순하게 만드는 방법으로, 결과적으로 작동하는 데이터 문자열에 대한 몇 가지 가정을 사용해야합니다.

이 방법 사용의 단점 : ASCII 표의 시작 부분에서 이러한 기호와 같은 일부 ASCII 문자로 작업하는 경우 다음 줄이 실패 할 수 있지만 직면 해 보자. 어쨌든 절대로 사용하지는 않을 것입니다.

이 방법을 사용하는 장점 : 대부분의 사람들은 일반적으로 특이한 문자없이 일부 일반 문자열로 작업하며이 방법이 가장 간단하고 빠른 방법임을 기억하십시오.

Long에서 byte []로 :

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

byte []에서 Long으로 :

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

2
네크로 포스트 (necroposting)는 유감이지만, 그저 잘못입니다. 예 : String.valueOf (0) .getBytes () [0] == 0x30입니다. 놀라다! String # getBytes는 숫자가 아닌 ASCII 인코딩 숫자 기호를 반환합니다. '0'! = 0이지만 '0'== 0x30
Kirill Gamazkov

아마 당신이 내 전체 답변을 읽었다면 당신은 내가 답변 자체에서 그것에 대해 경고 한 것을 보았을 것입니다.
Yonatan Nir

1
아, 나는 중간 바이트 [] 데이터가 (거의) 불투명 한 것으로 취급되는 점을 놓쳤다. 이 시나리오에는 트릭이 필요합니다.
Kirill Gamazkov

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

비슷한 방법이 있습니다 short, int, float, 등 그런 다음 사용할 수 의 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 연산을받는 두 정수 값의 상위 및 하위 비트로 표현 될 수 있습니다. (가) 있습니다 toUnsignedLong으로부터입니다 Integer클래스와의 최초의 호출은 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.