如何使用Go读/写文件?

时间:2009-11-30 19:17:46

标签: file go

我一直在努力学习Go,但我一直难以尝试阅读和写入普通文件。

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

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

9 个答案:

答案 0 :(得分:446)

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

因为最近文件API发生了变化,而且大多数其他答案都不适用于Go 1.他们也会错过bufio这个重要的恕我直言。

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

从基础开始

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作为错误返回。任何其他错误都会导致恐慌。

使用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轻松灵活地进行读写,同时它可以处理幕后缓冲。

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

很容易就像馅饼!但只有在你确定自己没有处理大文件时才使用它。

答案 1 :(得分:43)

这是一个很好的版本:

package main

import (
  "io/ioutil"; 
  )


func main() {
  contents,_ := ioutil.ReadFile("plikTekstowy.txt")
  println(string(contents))
  ioutil.WriteFile("filename", contents, 0644)
}

答案 2 :(得分:26)

使用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解决方案之一(实际上是“基本的”解决方案)。不过,他们使用的缓冲区比他大得多。

答案 3 :(得分:10)

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

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

inName

答案 4 :(得分:9)

新方式

从 Go 1.16 开始,使用 s 将文件加载到内存,并使用 os.ReadFile 从内存写入文件。

小心使用 os.WriteFile,因为它会将整个文件读入内存。

os.ReadFile

答案 5 :(得分:8)

使用较新的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")
}

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

答案 6 :(得分:7)

试试这个:

package main

import (
  "io"; 
  )


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

答案 7 :(得分:1)

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

The docs

  

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

这不起作用吗?

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

答案 8 :(得分:1)

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

通过这种方式,您可以确定读取器将读取多少字节并检查返回以查看实际读取的字节数并正确处理任何错误。

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

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