歡迎來到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