在本教程中,我们将学习如何使用 Go 将数据写入文件。我们还将学习如何同时向一个文件写入数据。

本教程包含以下部分

  • 将字符串写入文件


  • 将字节写入文件


  • 一行一行将数据写入文件


  • 添加到文件


  • 并发写入文件


将字符串写入文件

最常见的文件写入操作之一是将字符串写入文件。这很简单。它包括以下步骤。

  1. 创建文件


  1. 将字符串写入文件

让我们马上看看代码吧。

  1. package main
  2. import (
  3. "fmt"
  4. "os"
  5. )
  6. func main() {
  7. f, err := os.Create("test.txt")
  8. if err != nil {
  9. fmt.Println(err)
  10. return
  11. }
  12. l, err := f.WriteString("Hello World")
  13. if err != nil {
  14. fmt.Println(err)
  15. f.Close()
  16. return
  17. }
  18. fmt.Println(l, "bytes written successfully")
  19. err = f.Close()
  20. if err != nil {
  21. fmt.Println(err)
  22. return
  23. }
  24. }

上面的程序第 9 行 create 函数创建一个名为 test.txt 的文件。 如果已存在具有该名称的文件,则 create 函数会截断该文件。此函数返回文件描述符

第 14 行我们使用 WriteString 方法将字符串 Hello World 写入文件。 此方法返回写入的字节数和 error (如果有错误)。

最后在 21 行我们关闭文件

上面的程序将输出

  1. 11 bytes written successfully

你可以在执行此程序的目录中找到名为 test.txt 的文件。如果使用任何文本编辑器打开文件,则可以发现它包含文本 Hello World

将字节写入文件

将字节写入文件与将字符串写入文件非常相似。我们将使用 Write 方法将字节写入文件。以下程序将一片字节写入文件。

  1. package main
  2. import (
  3. "fmt"
  4. "os"
  5. )
  6. func main() {
  7. f, err := os.Create("/home/naveen/bytes")
  8. if err != nil {
  9. fmt.Println(err)
  10. return
  11. }
  12. d2 := []byte{104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100}
  13. n2, err := f.Write(d2)
  14. if err != nil {
  15. fmt.Println(err)
  16. f.Close()
  17. return
  18. }
  19. fmt.Println(n2, "bytes written successfully")
  20. err = f.Close()
  21. if err != nil {
  22. fmt.Println(err)
  23. return
  24. }
  25. }

在上面的程序中,第 15 行我们使用 Write 方法将一片字节写入目录 /home/naveen 中名为 bytes 的文件。 你可以将此目录更改为其他目录。 剩下的程序是一目了然的。 该程序将打印 bytes written successfully,并创建一个名为 bytes 的文件。 打开文件,你可以看到它包含文本 hello bytes

将字符串逐行写入文件


另一个常见的文件操作是需要逐行将字符串写入文件。在本节中,我们将编写一个程序来创建具有以下内容的文件。

  1. Welcome to the world of Go.
  2. Go is a compiled language.
  3. It is easy to learn Go.

让我们马上看看代码吧。

  1. package main
  2. import (
  3. "fmt"
  4. "os"
  5. )
  6. func main() {
  7. f, err := os.Create("lines")
  8. if err != nil {
  9. fmt.Println(err)
  10. f.Close()
  11. return
  12. }
  13. d := []string{"Welcome to the world of Go1.", "Go is a compiled language.", "It is easy to learn Go."}
  14. for _, v := range d {
  15. fmt.Fprintln(f, v)
  16. if err != nil {
  17. fmt.Println(err)
  18. return
  19. }
  20. }
  21. err = f.Close()
  22. if err != nil {
  23. fmt.Println(err)
  24. return
  25. }
  26. fmt.Println("file written successfully")
  27. }

程序第 9 行,我们创建一个名为 lines 的新文件。第 17 行我们使用 for range 循环遍历数组,并使用 Fprintln 函数将行写入文件。 Fprintln 函数将 io.writer 作为参数并添加一个新行,正如我们想的那样。 运行此程序将打印 file written successfully,并在当前目录中创建文件 lines 。 文件 lines 的内容如下所示。

  1. Welcome to the world of Go1.
  2. Go is a compiled language.
  3. It is easy to learn Go.


对文件进行追加

在本节中,我们将在我们在上一节中创建的 lines 文件中再添加一行。我们将添加 File handling is easylines 文件。

必须以追加和只写模式打开文件。传递这些标志的参数传递给 Open 函数。在追加模式下打开文件后,我们将新行添加到文件中。

  1. package main
  2. import (
  3. "fmt"
  4. "os"
  5. )
  6. func main() {
  7. f, err := os.OpenFile("lines", os.O_APPEND|os.O_WRONLY, 0644)
  8. if err != nil {
  9. fmt.Println(err)
  10. return
  11. }
  12. newLine := "File handling is easy."
  13. _, err = fmt.Fprintln(f, newLine)
  14. if err != nil {
  15. fmt.Println(err)
  16. f.Close()
  17. return
  18. }
  19. err = f.Close()
  20. if err != nil {
  21. fmt.Println(err)
  22. return
  23. }
  24. fmt.Println("file appended successfully")
  25. }

第 9 行我们以追加和只写模式打开文件。 文件成功打开后,我们第 15 行在文件中添加新行。 该程序将打印 file appended successfully。 运行此程序后,lines 文件的内容将是,

  1. Welcome to the world of Go1.
  2. Go is a compiled language.
  3. It is easy to learn Go.
  4. File handling is easy.


并发写入文件

当多个 goroutine 同时写入文件时,我们最终会遇到竞争条件。 因此,应该使用信道协调对文件的并发写入。

我们将编写一个创建 100 个 goroutines 的程序。 每个 goroutine 将同时生成一个随机数,从而总共生成一百个随机数。 这些随机数将写入文件。 我们将使用以下方法解决此问题。

  1. 创建一个信道,用于读取和写入生成的随机数。


  1. 创建 100 个生产者goroutines。每个 goroutine 将生成一个随机数,并将该随机数写入一个信道。


  1. 创建一个消费者 goroutine,它将从信道读取并将生成的随机数写入文件。因此,我们只有一个 goroutine 并发地写入文件,从而避免了竞争条件:)


  1. 一旦完成,关闭文件。

我们先写一下生成随机数的 produce 函数。

  1. func produce(data chan int, wg *sync.WaitGroup) {
  2. n := rand.Intn(999)
  3. data <- n
  4. wg.Done()
  5. }

上面的函数生成一个随机数并将其写入 data 信道,然后调用 waitgroup 上的 Done 函数,通知它已经完成了任务。

现在让我们转到写入文件的函数。

  1. func consume(data chan int, done chan bool) {
  2. f, err := os.Create("concurrent")
  3. if err != nil {
  4. fmt.Println(err)
  5. return
  6. }
  7. for d := range data {
  8. _, err = fmt.Fprintln(f, d)
  9. if err != nil {
  10. fmt.Println(err)
  11. f.Close()
  12. done <- false
  13. return
  14. }
  15. }
  16. err = f.Close()
  17. if err != nil {
  18. fmt.Println(err)
  19. done <- false
  20. return
  21. }
  22. done <- true
  23. }

consume 函数创建一个名为 concurrent 的文件。 然后它从 data 信道读取随机数并写入文件。 一旦它读取并写入了所有随机数,它就会向 done 信道写入 true ,以通知它完成了它的任务。

让我们编写 main 函数并完成该程序。 我在下面提供了整个程序。

  1. package main
  2. import (
  3. "fmt"
  4. "math/rand"
  5. "os"
  6. "sync"
  7. )
  8. func produce(data chan int, wg *sync.WaitGroup) {
  9. n := rand.Intn(999)
  10. data <- n
  11. wg.Done()
  12. }
  13. func consume(data chan int, done chan bool) {
  14. f, err := os.Create("concurrent")
  15. if err != nil {
  16. fmt.Println(err)
  17. return
  18. }
  19. for d := range data {
  20. _, err = fmt.Fprintln(f, d)
  21. if err != nil {
  22. fmt.Println(err)
  23. f.Close()
  24. done <- false
  25. return
  26. }
  27. }
  28. err = f.Close()
  29. if err != nil {
  30. fmt.Println(err)
  31. done <- false
  32. return
  33. }
  34. done <- true
  35. }
  36. func main() {
  37. data := make(chan int)
  38. done := make(chan bool)
  39. wg := sync.WaitGroup{}
  40. for i := 0; i < 100; i++ {
  41. wg.Add(1)
  42. go produce(data, &wg)
  43. }
  44. go consume(data, done)
  45. go func() {
  46. wg.Wait()
  47. close(data)
  48. }()
  49. d := <-done
  50. if d == true {
  51. fmt.Println("File written successfully")
  52. } else {
  53. fmt.Println("File writing failed")
  54. }
  55. }

main 函数在第 41 行创建从中读取和写入随机数的 data 信道。 consume goroutine 使用第 42 行的 done 信道来通知 main 它完成了它的任务。第 43 行 wg waitgroup用于等待所有 100 个 goroutine 完成生成随机数。

for 循环创建 100 个 goroutines。goroutine 调用 49 行 waitgroup 上的 wait() 等待所有 100 个 goroutine 完成创建随机数。 之后它关闭了信道。 一旦信道关闭并且consume goroutine 已经完成将所有生成的随机数写入文件,第 37 行它将 true 写入 done 信道并且主 goroutine 被解除阻塞并打印 File written successfully。

现在你可以在任何文本编辑器中打开文件 concurrent ,并查看 100 个生成的随机数:)

原文链接

https://golangbot.com/write-files/