Как я могу преобразовать 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[] 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;
}
result |= b[i]
байтовое значение будет сначала преобразовано в длинное, которое подписывает расширение. Байт со значением -128 (шестнадцатеричный 0x80
) превратится в длинный со значением -128 (шестнадцатеричный 0xFFFF FFFF FFFF FF80
). Сначала после преобразования находятся значения или: вместе. Использование побитовых и защищает от этого сначала преобразовать байты в междунар и отрезав знаковое расширение: (byte)0x80 & 0xFF ==> (int)0xFFFF FF80 & 0xFF ==> (int) 0x80
. Почему байты подписываются в Java, для меня немного загадка, но я думаю, что это подходит для других типов.
Если вы ищете быструю развернутую версию, это должно сработать, предполагая, что байтовый массив с именем "b" имеет длину 8:
байт [] -> длинный
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, а не 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[]
просто средство для достижения этой цели.
ByteBuffer
который в соответствии с документами "Первоначальный порядок байтового буфера всегда BIG_ENDIAN.
Просто запишите long в 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
и его потоки
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.
Я полагаю, что лицензия на программное обеспечение позволяет вам брать части кода и использовать его, но, пожалуйста, проверьте это.
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;
}
Я добавлю другой ответ, который является самым быстрым из возможных possible (да, даже больше, чем принятый ответ), НО он не будет работать для каждого отдельного случая. ОДНАКО, это будет работать для каждого мыслимого сценария:
Вы можете просто использовать String в качестве промежуточного звена. Обратите внимание, что это даст вам правильный результат, даже если кажется, что использование String может привести к неверным результатам, поскольку вы знаете, что работаете с «нормальными» строками. Это метод повышения эффективности и упрощения кода, который, в свою очередь, должен использовать некоторые допущения в отношении строк данных, с которыми он работает.
Против использования этого метода: если вы работаете с некоторыми символами ASCII, такими как эти символы, в начале таблицы ASCII, следующие строки могут не работать, но давайте посмотрим правде в глаза - вы, вероятно, никогда не будете их использовать.
Преимущество использования этого метода: Помните, что большинство людей обычно работают с некоторыми обычными строками без каких-либо необычных символов, и тогда этот метод - самый простой и быстрый способ.
от длинного к байтовому []:
byte[] arr = String.valueOf(longVar).getBytes();
от байта [] к длинному:
long longVar = Long.valueOf(new String(byteArr)).longValue();
Если вы уже используете 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 на приемной стороне.
С ByteBuffer.allocate (8) .putLong (obj) .array ():
public byte[] toBytes(Long obj) {
if (obj != null) {
return ByteBuffer.allocate(8).putLong(obj).array();
return null;
}
Источник:
Для многих других примеров использования ByteBuffer:
Вот еще один способ перейти 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
может быть выражено как биты старшего и младшего разрядов двух целочисленных значений, для которых применяется побитовое ИЛИ. Обратите внимание, что toUnsignedLong
это из Integer
класса, и первый вызов toUnsignedLong
может быть излишним.
Противоположное преобразование может быть также развернуто, как уже упоминали другие.
Расширения 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