Как преобразовать Long в byte [] и обратно в java

Как преобразовать long в byte[] и обратно в Java?

Я пытаюсь преобразовать long в byte[], чтобы я мог отправить byte[] через TCP-соединение. С другой стороны, я хочу взять этот byte[] и преобразовать его обратно в double.


person Emre801    schedule 19.12.2010    source источник
comment
Другой альтернативой будет Maps.transformValues, общий инструмент для преобразования коллекций. docs.guava- библиотеки.googlecode.com/git-history/release/javadoc/   -  person Raul    schedule 18.12.2012
comment
См. Также stackoverflow.com/q/27559449/32453, если ваша цель - преобразовать длинное число в наименьшее количество символов Base64. .   -  person rogerdpack    schedule 30.05.2016
comment
Возможно, следует подчеркнуть, что конвейер преобразования является «длинным -› байтом [] - ›двойным», а не «длинным -› байтом [] - ›длинным -› двойным ».   -  person Kirill Gamazkov    schedule 17.03.2017


Ответы (13)


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

Или завернутый в класс, чтобы избежать повторного создания ByteBuffers:

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-решений. Я думаю, что главное в моем ответе - это то, что вам не нужно самому беспокоиться о порядке байтов в системе.

person Brad Mace    schedule 19.12.2010
comment
Умно ... но вы создаете и удаляете временный ByteBuffer для каждого преобразования. Не годится, если вы отправляете несколько длинных запросов на одно сообщение и / или много сообщений. - person Stephen C; 20.12.2010
comment
@Stephen - я просто делал достаточно, чтобы продемонстрировать, как использовать ByteBuffer, но я пошел дальше и добавил пример использования его в служебном классе. - person Brad Mace; 20.12.2010
comment
Я думаю, что здесь bytesToLong () не сработает, поскольку позиция после вставки находится в конце буфера, а не в начале. Я думаю, вы получите исключение переполнения буфера. - person Alex Miller; 01.09.2011
comment
@BradMace, не могли бы вы отредактировать свой ответ, этот ответ неверен по мнению Алекса Миллера, и, используя ваш метод [static long bytesToLong (bytes)], я столкнулся с проблемами .. Вы должны были поместить байты в правильное место или очистить буфер. Я получал исключение BufferOverflowException. - person nullptr; 18.12.2012
comment
Отличный ответ. Мне было не сразу понятно, зачем нужно переворачивать, но я наткнулся на эту статью, которая мне очень помогла! tutorials.jenkov.com/java-nio/buffers.html Возможно, flip - это неправильное употребление? - person Reinstate Monica 2331977; 01.11.2013
comment
До Java 8 вы можете использовать Long.SIZE / Byte.SIZE вместо Long.BYTES, чтобы избежать магического числа. - person jvdbogae; 16.07.2014
comment
Повторное использование этого байтового буфера очень проблематично, и не только из соображений безопасности потоков, как отмечали другие. Мало того, что между ними потребуется '.clear ()', но что не очевидно, так это то, что вызов .array () в ByteBuffer возвращает резервный массив, а не копию. Таким образом, если вы вызываете несколько раз и удерживаете другие результаты, на самом деле это один и тот же массив, который многократно перезаписывает предыдущие значения. Ссылка на hadoop в комментарии ниже является наиболее эффективной и позволяет избежать любой из этих проблем. - person Aaron Zinman; 05.11.2014
comment
У кого-нибудь еще возникают проблемы с java.nio.BufferOverflowException? - person Snipe3000; 09.04.2021

Вы можете использовать методы преобразования байтов из Google Guava.

Пример:

byte[] bytes = Longs.toByteArray(12345L);
person Sonson123    schedule 09.01.2014

Я тестировал метод 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[] b) {
    long result = 0;
    for (int i = 0; i < 8; i++) {
        result <<= 8;
        result |= (b[i] & 0xFF);
    }
    return result;
}

Для Java 8+ мы можем использовать добавленные статические переменные:

public static byte[] longToBytes(long l) {
    byte[] result = new byte[Long.BYTES];
    for (int i = Long.BYTES - 1; i >= 0; i--) {
        result[i] = (byte)(l & 0xFF);
        l >>= Byte.SIZE;
    }
    return result;
}

public static long bytesToLong(final byte[] b) {
    long result = 0;
    for (int i = 0; i < Long.BYTES; i++) {
        result <<= Byte.SIZE;
        result |= (b[i] & 0xFF);
    }
    return result;
}
person Wytze    schedule 18.03.2015
comment
Вместо результата | = (b [i] & 0xFF); Мы могли бы просто использовать результат | = b [i]; as и с 0xFF для бита ничего не меняют. - person Vipul; 03.08.2015
comment
@Vipul Побитовое-и имеет значение, потому что при выполнении просто result |= b[i] байтовое значение сначала будет преобразовано в long, что означает расширение знака. Байт со значением -128 (шестнадцатеричный 0x80) превратится в длинный со значением -128 (шестнадцатеричный 0xFFFF FFFF FFFF FF80). Сначала после преобразования идут значения или: ed вместе. Использование побитового и защищает от этого, сначала преобразуя байт в int и отсекая расширение знака: (byte)0x80 & 0xFF ==> (int)0xFFFF FF80 & 0xFF ==> (int) 0x80. Почему байты подписываются в java, для меня немного загадка, но я предполагаю, что это подходит для других типов. - person Brainstorm; 26.08.2015
comment
@Brainstorm Я пробовал случай -128 с | = b [i] и с | = (b [i] & 0xFF), и результаты такие же !! - person Mahmoud Hanafy; 28.02.2016
comment
Проблема в том, что байт продвигается до применения сдвига, что вызывает странные проблемы со знаковым битом. Поэтому мы сначала и (&) его с 0xFF, чтобы получить правильное значение для сдвига. - person Wytze; 29.02.2016
comment
Я пытаюсь преобразовать эти данные (data = new byte [] {(byte) 0xDB, (byte) 0xA7, 0x53, (byte) 0xF8, (byte) 0xA8, 0x0C, 0x66, 0x8};) в длинные, но они возвращают ложное значение -2619032330856274424, ожидаемое значение 989231983928329832 - person jefry jacky; 28.07.2017
comment
Шестнадцатеричное представление 989231983928329832 - 0DBA753F8A80C668. Ведущий 0, вероятно, выпал из-за ошибки преобразования. - person Wytze; 29.07.2017
comment
это то же самое, что и из гугл гуава. по крайней мере, первое. это должно быть безопасно. - person mmm; 21.09.2020
comment
Левый сдвиг на Long.BYTES неверен. Он не сообщает о намерениях. Это работает только по совпадению: Long.BYTES равно 8. Замените это на Integer, и это будет неправильно. Вместо этого сдвиг влево на Byte.SIZE. - person Christian Hujer; 04.12.2020
comment
Мой первоначальный ответ был кем-то отредактирован. Восстановил как было. - person Wytze; 05.12.2020

Если вы ищете быструю развернутую версию, это должно сработать, предполагая, что массив байтов с именем «b» имеет длину 8:

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)};
person Michael Böckling    schedule 22.12.2014
comment
Спасибо, самое лучшее! - person Miha_x64; 10.05.2020
comment
Это предполагает порядок байтов с прямым порядком байтов, и код long -> byte[], добавленный кем-то другим при последующем редактировании, не работает для отрицательных чисел: - / - person dnault; 18.06.2021

Зачем нужен байт []? почему бы просто не записать в сокет?

Я предполагаю, что вы имеете в виду long, а не Long, последний должен допускать нулевые значения.

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

DataInputStream dis = new DataInputStream(
     new BufferedInputStream(socket.getInputStream()));
long longValue = dis.readLong();
person Peter Lawrey    schedule 19.12.2010
comment
Он спросил, как вы конвертируете в byte [] и обратно. Хороший ответ, но не ответил на вопрос. Вы спрашиваете почему, потому что предполагаете, что в этом нет необходимости, но это неверное предположение. Что, если он занимается кросс-языковым или кроссплатформенным? DataOutputStream здесь не поможет. - person user1132959; 12.05.2013
comment
Если он занимается кросс-языками или кросс-платформенностью, то важна отправка байтов в известном порядке. Этот метод делает это (сначала записывает старший байт) в соответствии с документацией. В принятом ответе нет (он записывает их в текущем порядке в соответствии с документами). В вопросе указано, что он хочет отправить их по TCP-соединению. byte[] - это просто средство для достижения этой цели. - person Ian McLaird; 16.08.2013
comment
@IanMcLaird В принятом ответе используется известный порядок. Он создает новый ByteBuffer, который согласно документации Начальный порядок байтового буфера всегда BIG_ENDIAN. - person David Phillips; 26.05.2016

Я считаю этот метод наиболее удобным.

var b = BigInteger.valueOf(x).toByteArray();

var l = new BigInteger(b);
person HexllioN    schedule 30.09.2020

Просто напишите длинный в DataOutputStream с помощью лежащий в основе ByteArrayOutputStream. Из 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 вам не нужен байт [] вручную. Вы будете использовать Socket socket и его потоки.

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

вместо.

person Michael Konietzka    schedule 19.12.2010

Вы можете использовать реализацию в 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.

Я считаю, что лицензия на программное обеспечение позволяет вам брать части кода и использовать их, но, пожалуйста, убедитесь в этом.

person Marquez    schedule 12.09.2013
comment
Почему эта реализация использует XOR (^ =) вместо OR? github.com/apache/hbase/blob/master/hbase-common/src/main/java/ - person victtim; 28.08.2018

Я добавлю еще один ответ, который является наиболее быстрым из возможных ׂ (да, даже больше, чем принятый ответ), НО это не сработает для каждого отдельного случая. ОДНАКО, это БУДЕТ работать для любого мыслимого сценария:

Вы можете просто использовать String как промежуточное звено. Обратите внимание, это ДАЕТ вам правильный результат, даже если кажется, что использование String может дать неправильные результаты, ПОКОЛЬКО ВЫ ЗНАЕТЕ, ЧТО ВЫ РАБОТАЕТЕ С «НОРМАЛЬНЫМИ» СТРОКАМИ. Это метод повышения эффективности и упрощения кода, который, в свою очередь, должен использовать некоторые предположения о строках данных, с которыми он работает.

Недостаток этого метода: если вы работаете с некоторыми символами ASCII, такими как эти символы в начале таблицы ASCII, следующие строки могут не работать, но давайте посмотрим правде в глаза - вы, вероятно, никогда не будете их использовать в любом случае.

За использование этого метода: помните, что большинство людей обычно работают с некоторыми обычными строками без каких-либо необычных символов, и тогда этот метод является наиболее простым и быстрым.

от Long до byte []:

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

от byte [] до Long:

long longVar = Long.valueOf(new String(byteArr)).longValue();
person Yonatan Nir    schedule 14.11.2015
comment
Извините за некропостинг, но это неправильно. E. g. String.valueOf (0) .getBytes () [0] == 0x30. Сюрприз! String # getBytes вернет символы цифр в кодировке ASCII, а не цифры: '0'! = 0, но '0' == 0x30 - person Kirill Gamazkov; 11.03.2017
comment
Что ж, может быть, если бы вы прочитали мой ответ полностью, то увидели бы, что я предупреждал об этом в самом ответе ... - person Yonatan Nir; 12.03.2017
comment
Ах, я упустил момент, когда данные промежуточного байта [] обрабатываются как (почти) непрозрачные. Ваш трюк подойдет для этого сценария. - person Kirill Gamazkov; 17.03.2017

Расширения Kotlin для типов Long и ByteArray:

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

person Artem Botnev    schedule 08.04.2020

Если вы уже используете 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 на принимающей стороне.

person Matt Solnit    schedule 19.12.2010

Вот еще один способ конвертировать byte[] в long с помощью Java 8 или новее:

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

Преобразование long может быть выражено как биты старшего и младшего разряда двух целочисленных значений, подлежащих побитовой операции ИЛИ. Обратите внимание, что _5 _ относится к классу Integer, и первый вызов toUnsignedLong может оказаться излишним.

Противоположное преобразование также может быть развернуто, как упоминали другие.

person Dave Jarvis    schedule 28.02.2020

person    schedule
comment
вы можете пропустить ArrayList: public static byte [] longToBytes (long l) {long num = l; byte [] bytes = новый байт [8]; for (int i = bytes.length - 1, i ›= 0; i--) {bytes [i] = (byte) (num & 0xff); число ›› = 8; } return bytesp; } - person eckes; 16.11.2013
comment
Исходный метод не работает с отрицательными числами, поскольку он попадает в бесконечный цикл в while (l! = 0), метод @eckes не работает с числами больше 127, потому что он не учитывает отрицательные байты, превышающие 127, потому что они подписаны. - person Big_Bad_E; 18.05.2019