【问题标题】:Convert Slice of int64 to byte array and vice versa in GoLang在 GoLang 中将 int64 的 Slice 转换为字节数组,反之亦然
【发布时间】:2018-07-12 05:02:13
【问题描述】:

我需要将 int64 切片转换为 golang 中的字节数组。我可以成功地为单个 int64 做到这一点

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

如何为一片 int64 实现它?

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

【问题讨论】:

  • 您可能必须循环并逐个执行此操作
  • 对于每个 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..有关更简单的多路解复用示例,请参阅 play.golang.org/p/YVQOAG8-Xlm
  • @Ravi 把它写成答案。
  • 非常感谢,成功了 :) play.golang.org/p/OdRakHIk1PP

标签: go casting


【解决方案1】:

例如,

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]

【讨论】:

    【解决方案2】:

    对于每个 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 了解更简单的复用-解复用示例。

    【讨论】:

      【解决方案3】:

      如果您的机器也是小端(很常见),您可以使用 不安全的转换 快速完成此操作(不需要 for 循环)。下面是两个示例函数,它们处理最长为 2^32 字节的数组。您可以更改代码以处理更大的容量。

      当然,这使用了 unsafe 包,因此您可能需要修改它以返回副本而不是直接使用内存。如果对不安全指针不熟悉,可以学习here

      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]
      }
      

      【讨论】:

        【解决方案4】:

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

        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 等)转换为字节切片也应该很明显。

        【讨论】:

          猜你喜欢
          • 2015-02-16
          • 1970-01-01
          • 2013-11-11
          • 2013-03-26
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多