Как преобразовать long
в byte[]
и обратно в Java?
Я пытаюсь преобразовать long
в byte[]
, чтобы я мог отправить byte[]
через TCP-соединение. С другой стороны, я хочу взять этот byte[]
и преобразовать его обратно в double
.
Как преобразовать long
в byte[]
и обратно в Java?
Я пытаюсь преобразовать long
в byte[]
, чтобы я мог отправить byte[]
через TCP-соединение. С другой стороны, я хочу взять этот byte[]
и преобразовать его обратно в double
.
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-решений. Я думаю, что главное в моем ответе - это то, что вам не нужно самому беспокоиться о порядке байтов в системе.
Вы можете использовать методы преобразования байтов из Google Guava.
Пример:
byte[] bytes = Longs.toByteArray(12345L);
Я тестировал метод 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;
}
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
Long.BYTES
неверен. Он не сообщает о намерениях. Это работает только по совпадению: Long.BYTES
равно 8. Замените это на Integer, и это будет неправильно. Вместо этого сдвиг влево на Byte.SIZE
.
- person Christian Hujer; 04.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)};
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();
byte[]
- это просто средство для достижения этой цели.
- person Ian McLaird; 16.08.2013
ByteBuffer
, который согласно документации Начальный порядок байтового буфера всегда BIG_ENDIAN.
- person David Phillips; 26.05.2016
Я считаю этот метод наиболее удобным.
var b = BigInteger.valueOf(x).toByteArray();
var l = new BigInteger(b);
Просто напишите длинный в 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 ..
вместо.
Вы можете использовать реализацию в org.apache.hadoop.hbase.util.Bytes http://hbase.apache.org/apidocs/org/apache/hadoop/hbase/util/Bytes.html
Исходный код здесь:
Найдите методы toLong и toBytes.
Я считаю, что лицензия на программное обеспечение позволяет вам брать части кода и использовать их, но, пожалуйста, убедитесь в этом.
Я добавлю еще один ответ, который является наиболее быстрым из возможных ׂ (да, даже больше, чем принятый ответ), НО это не сработает для каждого отдельного случая. ОДНАКО, это БУДЕТ работать для любого мыслимого сценария:
Вы можете просто использовать String как промежуточное звено. Обратите внимание, это ДАЕТ вам правильный результат, даже если кажется, что использование String может дать неправильные результаты, ПОКОЛЬКО ВЫ ЗНАЕТЕ, ЧТО ВЫ РАБОТАЕТЕ С «НОРМАЛЬНЫМИ» СТРОКАМИ. Это метод повышения эффективности и упрощения кода, который, в свою очередь, должен использовать некоторые предположения о строках данных, с которыми он работает.
Недостаток этого метода: если вы работаете с некоторыми символами ASCII, такими как эти символы в начале таблицы ASCII, следующие строки могут не работать, но давайте посмотрим правде в глаза - вы, вероятно, никогда не будете их использовать в любом случае.
За использование этого метода: помните, что большинство людей обычно работают с некоторыми обычными строками без каких-либо необычных символов, и тогда этот метод является наиболее простым и быстрым.
от Long до byte []:
byte[] arr = String.valueOf(longVar).getBytes();
от byte [] до Long:
long longVar = Long.valueOf(new String(byteArr)).longValue();
Расширения 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
Если вы уже используете 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 на принимающей стороне.
Вот еще один способ конвертировать 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
может оказаться излишним.
Противоположное преобразование также может быть развернуто, как упоминали другие.