首页 文章

如何使用Go读/写文件?

提问于
浏览
253

我一直在努力学习Go,但我一直难以尝试从普通文件中读取和写入 .

我可以得到 inFile, _ := os.Open(INFILE, 0, 0) ,但实际上获取文件的内容没有意义,因为read函数将 []byte 作为参数 .

func (file *File) Read(b []byte) (n int, err Error)

8 回答

  • 26

    Read方法接受一个byte参数,因为这是它将读入的缓冲区 . 在某些圈子里,它是一种常见的成语,当你想到它时会有所帮助 .

    这样,您可以确定读取器将读取多少字节并检查返回以查看实际读取的字节数并适当地处理任何错误 .

    正如其他人在他们的回答中指出的那样,bufio可能就是你想从大多数文件中读取的内容 .

    我将添加另一个提示,因为它非常有用 . 从文件中读取一行最好不是通过ReadLine方法完成,而是通过ReadBytes或ReadString方法完成 .

  • 423

    试试这个:

    package main
    
    import (
      "io"; 
      )
    
    
    func main() {
      contents,_ := io.ReadFile("filename");
      println(string(contents));
      io.WriteFile("filename", contents, 0644);
    }
    
  • 1

    看看文档,看起来你应该只声明一个[]字节类型的缓冲区并将其传递给read,然后读取那多个字符并返回实际读取的字符数(以及错误) .

    The docs

    读取从文件中读取最多len(b)个字节 . 它返回读取的字节数和错误(如果有) . EOF通过零计数发出信号,错误设置为EOF .

    这不起作用吗?

    编辑:另外,我认为您应该使用bufio包中声明的Reader / Writer接口而不是使用os包 .

  • 6

    让我们创建一个Go 1兼容的列表,列出在Go中读取和写入文件的所有方法 .

    因为文件API最近已经改变,并且大多数其他答案不适用于Go 1.他们也错过 bufio 这是重要的恕我直言 .

    在以下示例中,我通过读取文件并写入目标文件来复制文件 .

    Start with the basics

    package main
    
    import (
        "io"
        "os"
    )
    
    func main() {
        // open input file
        fi, err := os.Open("input.txt")
        if err != nil {
            panic(err)
        }
        // close fi on exit and check for its returned error
        defer func() {
            if err := fi.Close(); err != nil {
                panic(err)
            }
        }()
    
        // open output file
        fo, err := os.Create("output.txt")
        if err != nil {
            panic(err)
        }
        // close fo on exit and check for its returned error
        defer func() {
            if err := fo.Close(); err != nil {
                panic(err)
            }
        }()
    
        // make a buffer to keep chunks that are read
        buf := make([]byte, 1024)
        for {
            // read a chunk
            n, err := fi.Read(buf)
            if err != nil && err != io.EOF {
                panic(err)
            }
            if n == 0 {
                break
            }
    
            // write a chunk
            if _, err := fo.Write(buf[:n]); err != nil {
                panic(err)
            }
        }
    }
    

    在这里,我使用 os.Openos.Create 这些是 os.OpenFile 周围的方便包装 . 我们通常不需要直接调用 OpenFile .

    注意治疗EOF . Read 尝试在每次调用时填充 buf ,如果它到达文件末尾,则返回 io.EOF 作为错误 . 在这种情况下, buf 仍将保存数据 . 随后对 Read 的调用将返回零作为读取的字节数,并将 io.EOF 作为错误返回 . 任何其他错误都会导致恐慌 .

    Using bufio

    package main
    
    import (
        "bufio"
        "io"
        "os"
    )
    
    func main() {
        // open input file
        fi, err := os.Open("input.txt")
        if err != nil {
            panic(err)
        }
        // close fi on exit and check for its returned error
        defer func() {
            if err := fi.Close(); err != nil {
                panic(err)
            }
        }()
        // make a read buffer
        r := bufio.NewReader(fi)
    
        // open output file
        fo, err := os.Create("output.txt")
        if err != nil {
            panic(err)
        }
        // close fo on exit and check for its returned error
        defer func() {
            if err := fo.Close(); err != nil {
                panic(err)
            }
        }()
        // make a write buffer
        w := bufio.NewWriter(fo)
    
        // make a buffer to keep chunks that are read
        buf := make([]byte, 1024)
        for {
            // read a chunk
            n, err := r.Read(buf)
            if err != nil && err != io.EOF {
                panic(err)
            }
            if n == 0 {
                break
            }
    
            // write a chunk
            if _, err := w.Write(buf[:n]); err != nil {
                panic(err)
            }
        }
    
        if err = w.Flush(); err != nil {
            panic(err)
        }
    }
    

    bufio 在这里只是作为一个缓冲区,因为我们与数据没什么关系 . 在大多数其他情况下(特别是文本文件) bufio 非常有用,它可以让我们a nice API轻松灵活地进行读写,同时它可以处理幕后缓冲 .

    Using ioutil

    package main
    
    import (
        "io/ioutil"
    )
    
    func main() {
        // read the whole file at once
        b, err := ioutil.ReadFile("input.txt")
        if err != nil {
            panic(err)
        }
    
        // write the whole body at once
        err = ioutil.WriteFile("output.txt", b, 0644)
        if err != nil {
            panic(err)
        }
    }
    

    非常简单!但只有当你确定你没有处理大文件时才使用它 .

  • 10

    []byte 是字节数组的全部或部分的切片(类似于子字符串) . 将切片视为具有隐藏指针字段的值结构,以便系统定位和访问数组(切片)的全部或部分,以及切片的长度和容量的字段,您可以使用 len()cap() 功能 .

    这是一个适合您的入门套件,可读取并打印二进制文件;您需要更改 inName 文字值以引用系统上的小文件 .

    package main
    import (
        "fmt";
        "os";
    )
    func main()
    {
        inName := "file-rw.bin";
        inPerm :=  0666;
        inFile, inErr := os.Open(inName, os.O_RDONLY, inPerm);
        if inErr == nil {
            inBufLen := 16;
            inBuf := make([]byte, inBufLen);
            n, inErr := inFile.Read(inBuf);
            for inErr == nil {
                fmt.Println(n, inBuf[0:n]);
                n, inErr = inFile.Read(inBuf);
            }
        }
        inErr = inFile.Close();
    }
    
  • 42

    这是一个很好的版本:

    package main
    
    import (
      "io/ioutil"; 
      )
    
    
    func main() {
      contents,_ := ioutil.ReadFile("plikTekstowy.txt")
      println(string(contents))
      ioutil.WriteFile("filename", contents, 0644)
    }
    
  • 1

    Using io.Copy

    package main
    
    import (
        "io"
        "log"
        "os"
    )
    
    func main () {
        // open files r and w
        r, err := os.Open("input.txt")
        if err != nil {
            panic(err)
        }
        defer r.Close()
    
        w, err := os.Create("output.txt")
        if err != nil {
            panic(err)
        }
        defer w.Close()
    
        // do the actual work
        n, err := io.Copy(w, r)
        if err != nil {
            panic(err)
        }
        log.Printf("Copied %v bytes\n", n)
    }
    

    如果您不想重新发明轮子, io.Copyio.CopyN 可能会为您提供良好的服务 . 如果你是io.Copy函数的check the source,它只是在Go库中打包的Mostafa 's solutions (the ' basic之一 . 不过,他们使用的缓冲区比他大得多 .

  • 6

    使用较新的Go版本,可以轻松读取/写入文件 . 要从文件中读取:

    package main
    
    import (
        "fmt"
        "io/ioutil"
    )
    
    func main() {
        data, err := ioutil.ReadFile("text.txt")
        if err != nil {
            return
        }
        fmt.Println(string(data))
    }
    

    要写入文件:

    package main
    
    import "os"
    
    func main() {
        file, err := os.Create("text.txt")
        if err != nil {
            return
        }
        defer file.Close()
    
        file.WriteString("test\nhello")
    }
    

    这将覆盖文件的内容(如果不存在,则创建一个新文件) .

相关问题