写文件
写入字符串
经常会遇到向文件中写入字符串的需求,实现起来很简单,包括如下两步:
创建文件
将字符串写入创建的文件
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
}
}
通过os.Create
函数,创建了文件test.txt
,该函数返回了创建的文件的文件描述符。注意,如果要创建的文件名称已存在,存在的文件会被删除。我们通过WriteString
方法向文件中写入了字符串Hello World 你好 世界
,该方法返回写入的字符串的字节数。最后注意通过f.Close()
关闭文件。该程序执行输出:
25 bytes written successfully
同时生成一个文件test.txt
,包含文本Hello World 你好 世界
。
写入字节
向文件中写入字节跟写入字符串类似。使用Write
方法即可。下面的程序将一个切片的字节写入到文件中。
package main
import (
"fmt"
"os"
)
func main() {
f, err := os.Create("bytes.txt")
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
}
}
这里我们打开文件后,通过Write
方法将一个切片的字节写入文件。该程序执行输出:
11 bytes written successfully
同时创建了文件bytes.txt
,包含文本hello world
。
按行写入字符串
下面我们将如下几行字符串按行写入文件。
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.txt")
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")
}
这里我们还是通过os.Create()
来创建了一个文件。接着通过Fprintln
函数将一行一行的字符串写入到了文件中。最后关闭了文件。该程序执行输出:
file written successfully
同时创建了文件lines.txt
,包含了三行文本。
追加写入字符串
下面我们将下面这行文本追加写入到前面创建的文件lines.txt
中。
File handling is easy
要追加写入一个文件,该文件必须以追加模式打开。OpenFile
函数的参数可配置以哪种模式打开文件。
package main
import (
"fmt"
"os"
)
func main() {
f, err := os.OpenFile("lines.txt", 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")
}
这里我们给函数OpenFile
传入了os.O_APPEND|os.O_WRONLY
表示追加+仅写模式。该程序执行输出:
file appended successfully
同时在文件lines.txt
最后追加了一行文本File handling is easy.
。
并发写文件
如果多个goroutine
并发的向同一个文件写入,会出现竞态问题。这种情况下我们需要通过channel
,来将所有goroutine
要写入的数据做一个顺序化,跟排队类似。这本质上其实也是生产消费模型。
下面我们创建100个goroutine
,在每个goroutine
中并发的生成一个随机数,然后放入到channel
中。在channel
的接收端会收到来自各个goroutine
要写入的数据,然后依次无冲突的写入到文件中。
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.txt")
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")
}
}
这里的核心思想就是生产、消费模型,produce
协程函数用来生产数据,consume
协程用来消费数据。这里我们通过wg.Wait()
在所有生产者完成生产后调用close
关闭了channel
。同时我们在consume
协程中不断读取channel
中的数据,直到channel
被关闭。consume
协程完成按序写后调用f.Close()
关闭了文件。该程序执行输出为:
File written successfully
同时创建了文件concurrent.txt
,包含100行随机数字。
Last updated
Was this helpful?