Golang:从tar中提取的文件引发权限错误

I've written the following code to tar a file, code works but strangely if I untar the archive the file permissions are gone so I can't read it unless I then chmod the file:

package main

import (
    "archive/tar"
    "io/ioutil"
    "log"
    "os"
)

func main() {

    c, err := os.Create("/path/to/tar/file/test.tar")
    if err != nil {
        log.Fatalln(err)
    }

    tw := tar.NewWriter(c)

    f, err := os.Open("sample.txt")
    if err != nil {
        log.Fatalln(err)
    }

    fi, err := f.Stat()
    if err != nil {
        log.Fatalln(err)
    }

    hdr := &tar.Header{Name: f.Name(),
        Size: fi.Size(),
    }
    if err := tw.WriteHeader(hdr); err != nil {
        log.Fatalln(err)
    }

    r, err := ioutil.ReadFile("sample.txt")
    if err != nil {
        log.Fatalln(err)
    }

    if _, err := tw.Write(r); err != nil {
        log.Fatalln(err)
    }
    if err := tw.Close(); err != nil {
        log.Fatalln(err)
    }

}

Any idea what I'm doing wrong?

You're not preserving the original permissions of the file. You're manually creating a header, and specifying only the name and size. Instead, use tar.FileInfoHeader to build the header.

package main

import (
    "archive/tar"
    "io/ioutil"
    "log"
    "os"
)

func main() {
    c, err := os.Create("/path/to/tar/file/test.tar")
    if err != nil {
        log.Fatalln(err)
    }

    tw := tar.NewWriter(c)

    f, err := os.Open("sample.txt")
    if err != nil {
        log.Fatalln(err)
    }

    fi, err := f.Stat()
    if err != nil {
        log.Fatalln(err)
    }
    // create header from FileInfo
    hdr, err := tar.FileInfoHeader(fi, "")
    if err != nil {
        log.Fatalln(err)
    }
    if err := tw.WriteHeader(hdr); err != nil {
        log.Fatalln(err)
    }
    // instead of reading the whole file into memory, prefer io.Copy
    r, err := io.Copy(tw, f)
    if err != nil {
        log.Fatalln(err)
    }
    log.Printf("Wrote %d bytes
", r)
}

Also note that I used io.Copy to copy data from the file (an io.Reader) to the tar writer (an io.Writer). This will work much better for larger files.

Also - pay special attention to this note from the docs:

Because os.FileInfo's Name method returns only the base name of the file it describes, it may be necessary to modify the Name field of the returned header to provide the full path name of the file.

In this simple example, you're just using sample.txt so you shouldn't run into trouble. If you wanted to preserve a directory structure in your tar, you may have to modify the Name field in the header.