欢迎来到Golang系列教程的第36章。git
在这一章咱们将学习如何使用GO语言将数据写到文件里面。 而且还要学习如何同步的写到文件里面。github
这章教程包括以下几个部分:golang
将string写入文件 将bytes写入文件 将数据一行一行的写入文件 追加到文件里 同步写文件
请在本地运行全部本教程的程序,由于playground对文件的操做支持的并很差。数组
最多见的写文件就是将string写入文件。 这个写起来很是的简单。 这个包涵如下几个阶段。app
建立文件 将string写入文件
咱们将获得以下代码。编辑器
package main import ( "fmt" "os" ) func main() { f, err := os.Create("test.txt") if err != nil { fmt.Println(err) return } l, err := f.WriteString("Hello World") if err != nil { fmt.Println(err) f.Close() return } fmt.Println(l, "bytes written successfully") err = f.Close() if err != nil { fmt.Println(err) return } }
在第9行使用create
建立一个名字为test.txt
的文件.若是这个文件已经存在,那么create
方法将截断这个文件.方法返回文件的句柄.学习
在第14行,咱们使用WriteString
将字符串Hello World
写入到文件里面. 这个方法将返回相应写入的字节个数,若是有错误则返回错误.code
在第21行的时候将文件关闭.blog
上面程序的运行结果以下:教程
11 bytes written successfully
运行完成以后你会在程序运行的目录下发现建立了一个test.txt的文件.若是你使用文本编辑器打开这个文件,你能够看到文件里面有一个Hello World
的字符串.
将字节写入文件和写入字符串很是的相似. 咱们将使用Write
方法将字节写入到文件. 下面的程序将一个字节的切片写入文件.
package main import ( "fmt" "os" ) func main() { f, err := os.Create("/home/naveen/bytes") if err != nil { fmt.Println(err) return } d2 := []byte{104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100} n2, err := f.Write(d2) if err != nil { fmt.Println(err) f.Close() return } fmt.Println(n2, "bytes written successfully") err = f.Close() if err != nil { fmt.Println(err) return } }
在上面的程序中,第15行使用了Write
方法将字符切片写入到bytes
这个文件里. 这个文本在目录/home/naveen
目录里面. 你也能够将这个目录换成其余的目录.剩余的程序自带解释. 若是执行成功,这个程序将打印11 bytes written successfully
.而且建立一个bytes的文件.打开文件,你会发现该文件包含了hello
的字节.
另一个经常使用的操做就是将字符串一行一行的写入到文件.这一部分咱们将写一个程序,该程序建立并写入以下内容到文件里.
Welcome to the world of Go. Go is a compiled language. It is easy to learn Go.
让咱们看下面的代码:
package main import ( "fmt" "os" ) func main() { f, err := os.Create("lines") if err != nil { fmt.Println(err) f.Close() return } d := []string{"Welcome to the world of Go1.", "Go is a compiled language.", "It is easy to learn Go."} for _, v := range d { fmt.Fprintln(f, v) if err != nil { fmt.Println(err) return } } err = f.Close() if err != nil { fmt.Println(err) return } fmt.Println("file written successfully") }
在上面程序的第9行,咱们先建立一个名字叫作lines
的文件. 在第17行,咱们用迭代并使用for rang
循环这个数组, 并使用Fprintln
这个方法写入一行到文件里. 方法Fprintln
方法将io.writer
作为参数,而且添加一个新的行, 这个正是咱们想要的. 若是执行成功将打印file written successfully
, 而且在当前目录将建立一个lines
的文件.lines
这个文件的内容以下所示:
Welcome to the world of Go1. Go is a compiled language. It is easy to learn Go.
这一部分咱们将追加一行到lines
这个文件.咱们将追加File handling is easy
到lines
这个文件.
这个文件将以追加和写的方式打开. 这些标志将经过open
方法实现. 当文件以追加的方式打开, 咱们添加新的行到文件里.
package main import ( "fmt" "os" ) func main() { f, err := os.OpenFile("lines", os.O_APPEND|os.O_WRONLY, 0644) if err != nil { fmt.Println(err) return } newLine := "File handling is easy." _, err = fmt.Fprintln(f, newLine) if err != nil { fmt.Println(err) f.Close() return } err = f.Close() if err != nil { fmt.Println(err) return } fmt.Println("file appended successfully") }
在上面程序的第9行,咱们以写的方式打开文件并将一行添加到文件里. 当成功打开文件以后,在程序第15行,咱们添加一行到文件里. 程序成功将打印file appended successfully
. 运行程序,新的行就加到文件里面去了.
Welcome to the world of Go1. Go is a compiled language. It is easy to learn Go. File handling is easy.
当多个goroutines同时写文件时, 咱们须要使用同步锁解决. 当发生同步写的时候须要一个channel做为一致写入的条件.
咱们将写一个程序,该程序建立100个goroutinues. 每一个goroutinue将同时产生一个随机数,届时将有100个随机数产生. 这些随机数将被写入到文件里面. 咱们将用下面的方法解决这个问题.
建立一个channel用来读和写这个随机数. 建立100个用于生产的goroutine. 每一个goroutine将产生随机数并将随机数写入到channel里 建立一个用于消费的goroutine用来读取channel中的随机数. 这样的话咱们就只有一个goroutinue向文件中写数据,从而避免竞争的关系. 关闭文件.
咱们开始写产生随机数的方法:
func produce(data chan int, wg *sync.WaitGroup) { n := rand.Intn(999) data <- n wg.Done() }
上面的方法产生随机数而且将数据写入到channel中. 当完成以后经过waitGroup
通知其任务已经完成.
让咱们看看将数据写到文件的方法:
func consume(data chan int, done chan bool) { f, err := os.Create("concurrent") if err != nil { fmt.Println(err) return } for d := range data { _, err = fmt.Fprintln(f, d) if err != nil { fmt.Println(err) f.Close() done <- false return } } err = f.Close() if err != nil { fmt.Println(err) done <- false return } done <- true }
这个consume
的方法建立了一个concurrent
的文件. 而后从channel中读取写入的随机数而且写到文件中. 一旦读取完成而且将随机数写入文件后,将在done
这个channel中写入true
,而后通知其任务完成.
下面咱们写main
方法,并完成这个程序. 下面我提供完整的程序:
package main import ( "fmt" "math/rand" "os" "sync" ) func produce(data chan int, wg *sync.WaitGroup) { n := rand.Intn(999) data <- n wg.Done() } func consume(data chan int, done chan bool) { f, err := os.Create("concurrent") if err != nil { fmt.Println(err) return } for d := range data { _, err = fmt.Fprintln(f, d) if err != nil { fmt.Println(err) f.Close() done <- false return } } err = f.Close() if err != nil { fmt.Println(err) done <- false return } done <- true } func main() { data := make(chan int) done := make(chan bool) wg := sync.WaitGroup{} for i := 0; i < 100; i++ { wg.Add(1) go produce(data, &wg) } go consume(data, done) go func() { wg.Wait() close(data) }() d := <-done if d == true { fmt.Println("File written successfully") } else { fmt.Println("File writing failed") } }
main
方法在第41行建立建立写入和读取数据的channel, 在第42行建立done
这个channel, 此channel用于消费者goroutinue完成任务以后通知main
方法.第43行建立Waitgroup的实例wg
, 用于等待全部生产随机数的goroutine完成任务.
在第44行使用for
循环建立100个goroutines. 在第49行调用waitgroup的wait()
方法等待全部的goroutines完成随机数的生成. 而后关闭channel. 当channel关闭时,消费者的goroutine已经将全部的随机数写入文件,在第37行 的done
channel中写入true
. 这个时候main
方法解除阻塞而且打印File written successfully
.
这个时候你能够用任何的文本编辑器打开文件,能够看到100个随机数已经写入.
至此这篇教程就结束了,但愿你喜欢,祝你有美好的一天!
via: https://blog.golang.org/using-go-modules
做者:Naveen Ramanathan 译者:amei 校对:校对者ID