如何使用Go读/写文件?
我一直在努力学习去,但我一直试图读取和写入普通文件。
我可以得到尽可能inFile, _ := os.Open(INFILE, 0, 0)
,但实际上获取文件的内容是没有意义的,因为读取函数采用[]byte
作为参数。
func (file *File) Read(b []byte) (n int, err Error)
让我们制作一个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.Open
和os.Create
,它们是os.Create
方便的包装器。 我们通常不需要直接调用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
通过给我们一个很好的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) } }
易如反掌! 但是只有在确定你不处理大文件的情况下才能使用它。
这是好的版本:
package main import ( "io/ioutil"; ) func main() { contents,_ := ioutil.ReadFile("plikTekstowy.txt") println(string(contents)) ioutil.WriteFile("filename", contents, 0644) }
使用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.Copy
和io.CopyN
可以很好地为你服务。 如果你检查 io.Copy函数的源代码 ,它就是在Go库中打包的Mostafa解决scheme(实际上是“基本”的解决scheme)之一。 不过,他们正在使用比他大得多的缓冲区。
[]byte
是全部或部分字节数组的片(类似于子string)。 将切片想象成一个带有隐藏指针字段的值结构,以便系统定位和访问数组(切片)的全部或部分,以及切片的长度和容量的字段,您可以使用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(); }
尝试这个:
package main import ( "io"; ) func main() { contents,_ := io.ReadFile("filename"); println(string(contents)); io.WriteFile("filename", contents, 0x644); }
哪个新的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") }
这将覆盖文件的内容(如果不存在,则创build一个新文件)。
看看这个文档,你应该只是声明一个types为[]的缓冲区,然后传给它读取,然后读取那么多字符,并返回实际读取的字符数(以及一个错误)。
文档说
Read从文件读取len(b)个字节。 它返回读取的字节数和一个错误,如果有的话。 EOF通过零计数发送,err设置为EOF。
这不行吗?
编辑:另外,我想你也许应该使用bufio包中声明的Reader / Writer接口,而不是使用os包。
Read方法需要一个字节参数,因为那是它将读入的缓冲区。 在一些圈子里,这是一个普通的成语,当你思考这个问题的时候,它是有道理的。
通过这种方式,您可以确定读取器将读取多less个字节,并检查返回结果,以查看实际读取的字节数,并适当地处理任何错误。
正如其他人指出他们的答案bufio可能是你想要从大多数文件阅读。
我会添加一个其他提示,因为它非常有用。 从文件中读取一行最好不要使用ReadLine方法,而要使用ReadBytes或ReadString方法。