在Go语言中将int64切片转换为字节数组,反之亦然

4

我需要在golang中将int64切片转换为字节数组。对于单个int64,我已经成功地完成了转换。

var p int64 = -3984171602573983744
fmt.Println(p)
cn := make([]byte, 8)
binary.LittleEndian.PutUint64(cn, uint64(p))
fmt.Println(cn)

我该如何为int64切片实现它?

更准确地说,我正在尝试调用一个库中写入数据库的函数,该函数以字节数组作为参数。我有一个int64切片需要转换为字节数组,反之亦然。这是可能的吗?


你可能需要循环逐个执行这个操作。 - Derek Pollard
4
对于每个int64,循环并存储它,例如binary.LittleEndian.PutUint64(cn[x:], yourUint64),在循环过程中,x会变成0、8、16等。你的cn应该足够大以容纳所有数据(它将是8的某个倍数)。当你想要读取数据时,请执行相反操作,即x1 := binary.LittleEndian.Uint64(cn[n:n+8]),其中n变成0、1、2... 请参考https://play.golang.org/p/YVQOAG8-Xlm,查看一个更简单的多路复用-多路解复用示例。 - Ravi R
@Ravi,请将其作为答案编写。 - Charlie Tumahai
非常感谢,这解决了问题 :) https://play.golang.org/p/OdRakHIk1PP - Sumit Dhameja
可能是将字节切片转换为整数切片的重复问题。 - Martin Tournoij
4个回答

5
例如,
package main

import (
    "bytes"
    "encoding/binary"
    "fmt"
    "math"
)

func main() {

    w64 := []int64{math.MinInt64, -1, 0, 1, math.MaxInt64}
    fmt.Println(w64)

    // Write []int64 to database []byte
    wbuf := new(bytes.Buffer)
    err := binary.Write(wbuf, binary.LittleEndian, w64)
    if err != nil {
        fmt.Println("binary.Write failed:", err)
    }
    db := wbuf.Bytes()
    fmt.Printf("% x\n", db)

    // Read database []byte to []int64
    rbuf := bytes.NewBuffer(db)
    r64 := make([]int64, (len(db)+7)/8)
    err = binary.Read(rbuf, binary.LittleEndian, &r64)
    if err != nil {
        fmt.Println("binary.Read failed:", err)
    }
    fmt.Println(r64)
}

游乐场: https://play.golang.org/p/4OscSOGZE52

输出:

[-9223372036854775808 -1 0 1 9223372036854775807]
00 00 00 00 00 00 00 80 ff ff ff ff ff ff ff ff 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 ff ff ff ff ff ff ff 7f
[-9223372036854775808 -1 0 1 9223372036854775807]

1
对于每个int64的循环,请像这样存储:binary.LittleEndian.PutUint64(cn[x:], yourUint64),其中x变为0、8、16...随着循环的进行。您的cn应足够大以容纳所有数据(它将是8的某个倍数)。当您想要读取时,执行相反操作:x1 := binary.LittleEndian.Uint64(cn[n:n+8]),其中n变为0、1、2...。
请参见https://play.golang.org/p/YVQOAG8-Xlm,了解更简单的复用-分离示例。

0

我知道我回答这个问题有点晚,但是在寻找一个简单的答案时,它似乎没有做一些奇怪的魔法操作或不安全的指针操作,我最终创建了这段代码。希望它能对你有所帮助。

func convertInt64ToByteSlice(input int64) []byte {
    inputUint := uint64(input)
    ClearOctate8 := uint64(0b_00000000_00000000_00000000_00000000_00000000_00000000_00000000_11111111)

    result := []byte{
        byte(inputUint >> 56 & ClearOctate8),
        byte(inputUint >> 48 & ClearOctate8),
        byte(inputUint >> 40 & ClearOctate8),
        byte(inputUint >> 32 & ClearOctate8),
        byte(inputUint >> 24 & ClearOctate8),
        byte(inputUint >> 16 & ClearOctate8),
        byte(inputUint >> 8 & ClearOctate8),
        byte(inputUint >> 0 & ClearOctate8),
    }
    
    return result
}

当然,您可以返回一个8字节的数组而不是切片,但我需要使用切片,因此我已经将字节切片用作返回值。同时,使用其他整数类型(如int32或uint16等)转换为字节切片也应该非常明显。

0

如果你的机器也是小端序(相当普遍),你可以使用 unsafe conversion 来非常快速地完成此操作(不需要 for 循环)。这里有两个处理长达 2^32 字节数组的示例函数。你可以更改代码以处理更大的容量。

当然,这使用了 unsafe 包,所以你可能想修改它以返回副本而不是直接使用内存。如果你不熟悉不安全指针,你可以在 这里 学习。

func bytesToInt64s(buf []byte) []int64 {
    if len(buf) < 1 << 16 {
        return (*[1 << 13]int64)(unsafe.Pointer(&buf[0]))[0 : len(buf)/8 : len(buf)/8]
    }
    l := len(buf)
    if l > 1 << 32 { // only use the first 2^32 bytes
       l = (1 << 32) - 1
    }
    return (*[1 << 29]int64)(unsafe.Pointer(&buf[0]))[0 : l / 8 : l / 8 ]
}

func int64sToBytes(buf []int64) []byte {
    if len(buf) < 1 << 13 {
        return (*[1 << 16]byte)(unsafe.Pointer(&buf[0]))[0 : len(buf)*8 : len(buf)*8]
    }
    l := len(buf) * 8
    if l > 1 << 32 { // only use the first 2^32 bytes
       l = (1 << 32) - 1
    }
    return (*[1 << 32]byte)(unsafe.Pointer(&buf[0]))[0 : l : l]
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接