ChatGPT解决这个技术问题 Extra ChatGPT

如何将 Long 转换为 byte[] 并返回到 java

如何将 long 转换为 byte[] 并返回 Java?

我正在尝试将 long 转换为 byte[],以便能够通过 TCP 连接发送 byte[]。另一方面,我想把那个 byte[] 转换回 double

另一种选择是 Maps.transformValues,一种用于转换集合的通用工具。 docs.guava-libraries.googlecode.com/git-history/release/javadoc/…
如果您的目标是将 long 转换为最少数量的 Base64 字符,另请参阅 stackoverflow.com/q/27559449/32453

C
Community
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 这样的库。如果您对库有一些奇怪的反对意见,您可能应该首先考虑将 this answer 用于本机 Java 解决方案。我认为我的回答真正要解决的主要问题是您不必自己担心系统的字节序。


聪明...但是您为每次转换创建并丢弃一个临时 ByteBuffer。如果您在每条消息和/或大量消息中发送多个长消息,那就不好了。
@Stephen - 我只是做了足够的工作来演示如何使用 ByteBuffer,但我继续并添加了一个在实用程序类中使用它的示例。
我认为这里的 bytesToLong() 会失败,因为 put 之后的位置位于缓冲区的末尾,而不是开头。我想你会得到一个缓冲区下溢异常。
在 Java 8 之前,您可以使用 Long.SIZE/Byte.SIZE 而不是 Long.BYTES 来避免出现幻数。
该字节缓冲区的重用存在很大问题,而不仅仅是因为其他人评论的线程安全原因。不仅在两者之间需要“.clear()”,而且不明显的是,在 ByteBuffer 上调用 .array() 会返回支持数组而不是副本。因此,如果您重复调用并保留其他结果,它们实际上都是重复覆盖先前值的相同数组。下面评论中的 hadoop 链接是性能最高的,可以避免任何这些问题。
S
Sonson123

您可以使用 Google Guava 中的 Byte conversion methods

例子:

byte[] bytes = Longs.toByteArray(12345L);

W
Wytze

我针对普通的按位运算测试了 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;
}

而不是结果 |= (b[i] & 0xFF);我们可以简单地使用 result |= b[i];与 0xFF 一样,并不会修改任何内容。
@Vipul按位和确实很重要,因为仅执行 result |= b[i] 时,字节值将首先转换为 long 进行符号扩展。值为 -128(十六进制 0x80)的字节将变成值为 -128(十六进制 0xFFFF FFFF FFFF FF80)的长整数。转换后首先是值 or:ed 在一起。使用 bitwise-and 通过首先将字节转换为 int 并切断符号扩展名来防止这种情况:(byte)0x80 & 0xFF ==> (int)0xFFFF FF80 & 0xFF ==> (int) 0x80。为什么字节在 java 中被签名对我来说有点神秘,但我想它是为了适应其他类型。
@Brainstorm 我用 |= b[i] 和 |= (b[i] & 0xFF) 尝试了 case -128,结果是一样的!!
问题是字节在应用移位之前得到提升,这会导致符号位出现奇怪的问题。因此,我们首先用 0xFF (&) 它来获得正确的移位值。
我尝试将此数据 (data = new byte[]{(byte) 0xDB, (byte) 0xA7, 0x53, (byte) 0xF8, (byte) 0xA8, 0x0C, 0x66, 0x8}; ) 转换为 long,但它返回假值-2619032330856274424,期望值为989231983928329832
D
Dreamspace President

如果您正在寻找一个快速展开的版本,这应该可以解决问题,假设一个名为“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 -> byte[] 代码因负数而失败:-/
E
Evan Knowles

为什么需要字节[]?为什么不直接将其写入套接字?

我假设您的意思是长而不是长,后者需要允许空值。

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

DataInputStream dis = new DataInputStream(
     new BufferedInputStream(socket.getInputStream()));
long longValue = dis.readLong();

他问你如何转换为 byte[] 并返回。很好的答案,但没有回答问题。你问为什么,因为你认为这是不必要的,但这是一个错误的假设。如果他在做跨语言或跨平台呢? DataOutputStream 不会帮助你。
如果他正在做跨语言或跨平台,那么以已知顺序发送字节很重要。根据文档,这种方法可以做到这一点(它“先写高字节”)。接受的答案没有(它根据文档以“当前顺序”编写它们)。问题表明他想通过 TCP 连接发送它们。 byte[] 只是达到此目的的一种手段。
@IanMcLaird 接受的答案确实使用已知的顺序。它根据文档创建一个新的 ByteBuffer “字节缓冲区的初始顺序始终为 BIG_ENDIAN。
H
HexllioN

我觉得这种方法最友好。

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

var l = new BigInteger(b);

M
Michael Konietzka

只需将 long 写入具有基础 ByteArrayOutputStreamDataOutputStream。从 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 socket 及其流

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

反而。


M
Marquez

您可以使用 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 方法。

我相信软件许可证允许您获取部分代码并使用它,但请验证。


为什么该实现使用 XOR (^=) 而不是 OR? github.com/apache/hbase/blob/master/hbase-common/src/main/java/…
m
maziar
 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;
    }

您可以跳过 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);数 >>= 8; } 返回字节; }
原始方法不适用于负数,因为它在 while (l != 0) 中进入无限循环,@eckes 的方法不适用于超过 127 的数字,因为他不考虑字节数超过 127 的原因他们签署了。
Y
Yonatan Nir

我将添加另一个可能最快的答案 ׂ(是的,甚至比公认的答案还要多),但它不适用于每种情况。但是,它适用于所有可能的情况:

您可以简单地使用 String 作为中间体。请注意,这将为您提供正确的结果,即使看起来使用 String 可能会产生错误的结果,只要您知道您正在使用“正常”字符串。这是一种提高效率并使代码更简单的方法,作为回报,它必须对其操作的数据字符串使用一些假设。

使用此方法的缺点:如果您在 ASCII 表的开头使用一些 ASCII 字符,例如这些符号,以下行可能会失败,但让我们面对现实吧 - 您可能永远不会使用它们。

使用此方法的优点:请记住,大多数人通常使用一些没有任何异常字符的正常字符串,然后该方法是最简单和最快的方法。

从 Long 到 byte[]:

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

从 byte[] 到 Long:

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

很抱歉发布了 necroposting,但那是错误的。例如。 String.valueOf(0).getBytes()[0] == 0x30。惊喜! String#getBytes 将返回 ASCII 编码的数字符号,而不是数字:'0' != 0,但 '0' == 0x30
好吧,也许如果您已经阅读了我的全部答案,那么您会看到我在答案本身中已经警告过它..
啊,我错过了中间字节 [] 数据被视为(几乎)不透明的观点。您的技巧将适用于这种情况。
A
Artem Botnev

对于 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


M
Matt Solnit

如果您已经在使用 OutputStream 写入套接字,那么 DataOutputStream 可能是一个不错的选择。这是一个例子:

// Assumes you are currently working with a SocketOutputStream.

SocketOutputStream outputStream = ...
long longValue = ...

DataOutputStream dataOutputStream = new DataOutputStream(outputStream);

dataOutputStream.writeLong(longValue);
dataOutputStream.flush();

shortintfloat 等也有类似的方法。然后您可以在接收端使用 DataInputStream


D
Dave Jarvis

这是使用 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));
}

转换 long 可以表示为两个整数值的高位和低位进行按位或。请注意,toUnsignedLong 来自 Integer 类,第一次调用 toUnsignedLong 可能是多余的。

正如其他人所提到的,相反的转换也可以展开。


Q
Quân Anh Mai

从 Java 9 开始,最好的方法是使用 VarHandle,它将从字节数组中读取,就好像它是一个长数组一样,为了提高性能,使 VarHandle 实例成为静态最终字段。

static final VarHandle HANDLE = MethodHandles.byteArrayViewVarHandle(Long.TYPE.arrayType(), ByteOrder.nativeOrder());

static long bytesToLong(byte[] bytes, int offset) {
    return (long)HANDLE.get(bytes, offset);
}

static void longToBytes(byte[] bytes, int offset, long value) {
    HANDLE.set(bytes, offset, value);
}

E
Eric Aya

当前的所有答案都比它们需要的复杂得多,我讨厌任何找到此线程的人在没有更简洁的选择的情况下走开。

您可以在一行中完成这两种转换。

字节 [] 长:

ByteBuffer.wrap(yourBytes).getLong();

长到字节[]:

ByteBuffer.wrap(new byte[8]).putLong(yourLong).array();

A
Abdel
static byte[] longToBytes(Long l) {
    return (l + "").getBytes(StandardCharsets.UTF_8);
}

您的答案可以通过额外的支持信息得到改进。请edit添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。您可以找到有关如何写出好答案的更多信息in the help center