Як перетворити long
до byte[]
і назад в Java?
Я намагаюся перетворити a long
в byte[]
так, що я зможу надіслати byte[]
через TCP-з'єднання. З іншого боку, я хочу взяти це byte[]
і перетворити його назад в double
.
Як перетворити long
до byte[]
і назад в Java?
Я намагаюся перетворити a 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
). Першими після перетворення є значення або: ed разом. Використання побітових і захищає від цього спочатку перетворити байти в міжнародному і відрізавши знакове розширення: (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 , останній повинен враховувати нульові значення.
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.
Просто запишіть довгу в 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.
Я вважаю, що ліцензія на програмне забезпечення дозволяє вам брати частини коду та використовувати його, але будь ласка, переконайтесь у цьому.
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;
}
Я додам ще одну відповідь, яка є найшвидшою з можливих ׂ (так, навіть більше, ніж прийнята відповідь), Але вона не працюватиме для кожного окремого випадку. ЗНАЙДІ, це буде працювати для кожного можливого сценарію:
Ви можете просто використовувати String як проміжний. Зауважте, це дасть вам правильний результат, навіть якщо здається, що використання String може призвести до неправильних результатів, КАК ДОВІГО, ЯК ВИ ЗНАЄТИ, ЩО ВИ РОБОТИ З "НОРМАЛЬНИМИ" РУКАМИ. Це метод підвищення ефективності та спрощення коду, який взамін повинен використовувати деякі припущення щодо рядків даних, на яких він працює.
Що стосується використання цього методу: Якщо ви працюєте з деякими символами ASCII, такими як ці символи, на початку таблиці ASCII, наступні рядки можуть вийти з ладу, але визнаймо це - ви, ймовірно, ніколи їх не будете використовувати.
Про використання цього методу. Пам’ятайте, що більшість людей зазвичай працюють із звичайними рядками без будь-яких незвичних символів, і тоді метод є найпростішим і швидким способом.
від Long to byte []:
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));
}
Перетворення a 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