4

I need to convert a slice of int64 to a byte array in golang. I am successfully able to do so for a single int64

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

How can I implement it for a slice of int64?

To be more precise, I am trying to call a function in a library which writes to a DB, and that function takes a byte array as a param. I have a slice of int64 which I need to convert to a byte array and vice versa. Is this possible?

5
  • You will probably have to loop through and do this 1 by 1 Commented Jul 12, 2018 at 5:05
  • 4
    For each of the int64's loop and store it like binary.LittleEndian.PutUint64(cn[x:], yourUint64), where x becomes 0,8,16...as you loop. Your cn should be big enough to take all the data (it'll be some multiple of 8). When you want to read do the reverse x1 := binary.LittleEndian.Uint64(cn[n:n+8]), where n becomes 0, 1, 2..See play.golang.org/p/YVQOAG8-Xlm for a simpler muxing-demuxing example Commented Jul 12, 2018 at 5:49
  • @Ravi Write that as an answer. Commented Jul 12, 2018 at 5:55
  • Thanks a lot, that did the trick :) play.golang.org/p/OdRakHIk1PP Commented Jul 12, 2018 at 6:08
  • Possible duplicate of Convert byte slice to int slice Commented Jul 12, 2018 at 9:46

4 Answers 4

7

For example,

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

Playground: https://play.golang.org/p/4OscSOGZE52

Output:

[-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]
Sign up to request clarification or add additional context in comments.

Comments

1

For each of the int64's loop and store it like binary.LittleEndian.PutUint64(cn[x:], yourUint64), where x becomes 0,8,16...as you loop. Your cn should be big enough to take all the data (it'll be some multiple of 8). When you want to read, do the reverse: x1 := binary.LittleEndian.Uint64(cn[n:n+8]), where n becomes 0, 1, 2..

See https://play.golang.org/p/YVQOAG8-Xlm for a simpler muxing-demuxing example.

Comments

0

If your machine is also little endian (pretty common), you can use an unsafe conversion to do this very quickly (no for loop required). Here are two example functions that handle arrays up to 2^32 bytes long. You can change the code to handle larger capacities.

Of course, this uses the unsafe package, so you might want to modify this to return copies instead of using the memory directly. If you're not familiar with unsafe pointers, you can learn 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]
}

Comments

0

I know that I am late answering this question but after a lot of searching for a simple answer which does not seem to do some strange magic stuff or unsafe pointer operations, I ended up creating this piece of code. I hope it helps the cause.

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
}

You can of course return an array of 8 bytes instead of a slice, but I needed slices so I have used a byte slice as return value. It should also be pretty evident how to use other integer types (like int32 or uint16 etc.) to convert to a byte slice.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.