How to copy from slice to array with seeking onto slice

拟墨画扇 提交于 2021-02-08 03:44:25

问题


I'm writing a library to deal with a binary format.

I have a struct with array vars, that I would like to keep for documentation purposes.

I need also to seek and tell from the input slice of bytes.

Some pseudocode:

type foo struct {
    boo [5]byte
    coo [3]byte
}

func main() {

    // input is a []byte full of datas, read from a file

    var bar foo

    // Here i need something that writes 5 bytes to bar.foo from input
    bar.foo = somefunc(input, numberOfFoo) // ???
    // I need also tell() and seek()
    input.seek(n)

}

How can I do that with a single function?


回答1:


Operating on byte slice input

You may use the builtin copy() to copy bytes from a source slice into a destination. If you have an array, slice it to obtain a slice, e.g. bar.boo[:]. To seek, just use a different offset in the source slice, also by reslicing it, e.g. input[startPos:].

For example:

input := []byte{1, 2, 3, 4, 5, 0, 0, 8, 9, 10}

var bar foo
copy(bar.boo[:], input)

// Skip 2 bytes, seek to the 8th byte:
input = input[7:]

copy(bar.coo[:], input)

fmt.Printf("%+v", bar)

Output (try it on the Go Playground):

{boo:[1 2 3 4 5] coo:[8 9 10]}

Creating a ReadSeeker

Another option is to wrap your input byte slice into an io.ReadSeeker such as bytes.Reader, then you can read from it.

For example:

input := []byte{1, 2, 3, 4, 5, 0, 0, 8, 9, 10}
r := bytes.NewReader(input)

var bar foo
if _, err := io.ReadFull(r, bar.boo[:]); err != nil {
    panic(err)
}

// Skip 2 bytes, seek to the 8th byte:
if _, err := r.Seek(7, io.SeekStart); err != nil {
    panic(err)
}

if _, err := io.ReadFull(r, bar.coo[:]); err != nil {
    panic(err)
}

fmt.Printf("%+v", bar)

Output is the same, try it on the Go Playground.

Using encoding/binary

Yet another solution would be to use encoding/binary to read your whole struct in one step.

In order to do this, we need to export the fields, and we have to insert an anonymous or blank field that covers the skipped bytes:

type foo struct {
    Boo [5]byte
    _   [2]byte // don't care
    Coo [3]byte
}

Having the above type, we can read all of it in one step like this:

input := []byte{1, 2, 3, 4, 5, 0, 0, 8, 9, 10}
r := bytes.NewReader(input)

var bar foo
if err := binary.Read(r, binary.LittleEndian, &bar); err != nil {
    panic(err)
}

fmt.Printf("%+v", bar)

Output is similar, except that it also displays the anonymous field (try it on the Go Playground):

{Boo:[1 2 3 4 5] _:[0 0] Coo:[8 9 10]}

See related answer: Why use arrays instead of slices?

Reading directly from the original file

You mentioned your input slice is from reading a file. Note that you do not need to read the file prior, as os.File implements io.Reader, even io.ReadSeeker, which means you can read from it directly, see the Creating a ReadSeeker section. You can also directly apply the encoding/binary solution, as we used a reader in that solution too.



来源:https://stackoverflow.com/questions/53429405/how-to-copy-from-slice-to-array-with-seeking-onto-slice

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!