文章目录
go IO操作-文件写
函数介绍
os.OpenFile()
函数能够以指定模式打开文件,从而实现文件写入相关功能。
func OpenFile(name string, flag int, perm FileMode) (*File, error) {}
func Create(name string) (*File, error) {}
// 本质还是OpenFile--》return OpenFile(name, O_RDWR|O_CREATE|O_TRUNC, 0666)
flag参数介绍
模式 | 含义 |
---|---|
os.O_WRONLY | 只写 |
os.O_CREATE | 创建文件 |
os.O_RDONLY | 只读 |
os.O_RDWR | 读写 |
os.O_TRUNC | 清空 |
os.O_APPEND | 追加 |
写入文件
File.Write(将字节写入文件)
func main() {
file,err:=os.Create("lxx.txt")
if err != nil {
fmt.Println("打开文件错误:",err)
return
}
defer file.Close()
//d2 := []byte{104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100}
//d2 := []byte("hello world")
d2 := []byte{'h','e','l','l','o'}
n,err:=file.Write(d2)
if err != nil {
fmt.Println("写入文件出错:",err)
}
fmt.Printf("%d字节写入文件成功",n)
}
File.WriteString(将字符串写入文件)
func main() {
file,err:=os.Create("lxx.txt")
if err != nil {
fmt.Println("打开文件错误:",err)
return
}
defer file.Close()
s:="hello world"
n,err:=file.WriteString(s)
if err != nil {
fmt.Println("写入文件出错:",err)
}
fmt.Printf("%d字节写入文件成功",n)
}
ioutil.WriteFile写入文件
func main() {
err:=ioutil.WriteFile("lxx.txt",[]byte("lxx is nb"),0666)
if err != nil {
fmt.Println("写入文件出错",err)
return
}
}
bufio.NewWriter写入文件
func main() {
file,err:=os.OpenFile("lxx.txt",os.O_CREATE|os.O_WRONLY,0666)
if err != nil {
fmt.Println("打开文件出错:",err)
return
}
defer file.Close()
writer:=bufio.NewWriter(file)
writer.WriteString("lxx is handsome")
writer.Flush() // 从缓冲区写入硬盘
}
其他
一行行写入到文件
func main() {
file,err:=os.OpenFile("lxx.txt",os.O_CREATE|os.O_WRONLY,0666)
if err != nil {
fmt.Println("打开文件出错:",err)
return
}
defer file.Close()
d := []string{"Welcome to the world of Go", "Go is a compiled language.", "It is easy to learn Go."}
for _, v := range d {
fmt.Fprintln(file, v)
if err != nil {
fmt.Println(err)
return
}
}
}
追加到文件
// 只要打开文件:file,err:=os.OpenFile("lxx.txt",os.O_APPEND|os.O_WRONLY,0666)
func main() {
file,err:=os.OpenFile("lxx.txt",os.O_APPEND|os.O_WRONLY,0666)
if err != nil {
fmt.Println("打开文件出错:",err)
return
}
defer file.Close()
d := []string{"Welcome to the world of Go", "Go is a compiled language.", "It is easy to learn Go."}
for _, v := range d {
fmt.Fprintln(file, v)
if err != nil {
fmt.Println(err)
return
}
}
}
并发写文件
当多个 goroutines 同时(并发)写文件时,我们会遇到竞争条件(race condition)。因此,当发生同步写的时候需要一个 channel 作为一致写入的条件。
我们将写一个程序,该程序创建 100 个 goroutinues。每个 goroutinue 将并发产生一个随机数,届时将有 100 个随机数产生。这些随机数将被写入到文件里面。我们将用下面的方法解决这个问题 .
- 创建一个 channel 用来读和写这个随机数。
- 创建 100 个生产者 goroutine。每个 goroutine 将产生随机数并将随机数写入到 channel 里。
- 创建一个消费者 goroutine 用来从 channel 读取随机数并将它写入文件。这样的话我们就只有一个 goroutinue 向文件中写数据,从而避免竞争条件。
- 一旦完成则关闭文件。
我们开始写产生随机数的 produce
函数:
func produce(data chan int, wg *sync.WaitGroup) {
n := rand.Intn(999)
data <- n
wg.Done()
}
上面的方法产生随机数并且将 data
写入到 channel 中,之后通过调用 waitGroup
的 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
}
这个 consume
的函数创建了一个名为 concurrent
的文件。然后从 channel 中读取随机数并且写到文件中。一旦读取完成并且将随机数写入文件后,通过往 done
这个 cahnnel
中写入 true
来通知任务已完成。
下面我们写 main
函数,并完成这个程序。下面是我提供的完整程序:
package main
import (
"fmt"
"math/rand"
"os"
"sync"
)
// 生产者,每个生产者随机产生一个999内的数字
func producer(data chan int, wg *sync.WaitGroup) {
r := rand.Intn(999)
data <- r
wg.Done()
}
func consumer(data chan int, done chan bool) {
file, err := os.Create("concurrent") // 打开一个文件
if err != nil {
fmt.Println(err)
return
}
for d := range data {
_, err := fmt.Fprintln(file, d)
if err != nil {
fmt.Println("写入出错")
file.Close() // 关闭文件
done <- false // 成功标志中写入false
return
}
}
file.Close() // 在for循环外面关闭文件
done <- true
}
func main() {
var (
data = make(chan int)
done = make(chan bool)
wg sync.WaitGroup
)
// 启动1000个协程生产随机数
for i := 0; i < 1000; i++ {
wg.Add(1)
go producer(data,&wg)
}
// 开启消费者,往文件中写随机数
go consumer(data,done)
go func() { //在另一个协程中等待所有生产者完成,然后关闭数据信道,不能写在主协程中
wg.Wait()
close(data)
}()
// 从done中取出数据
res :=< -done
if res{ // true表示顺利写完
fmt.Println("顺利写完")
}else {// false 表示写出问题
fmt.Println("写出问题")
}
}
main
函数创建写入和读取数据的 channel,创建 done
这个 channel,此 channel 用于消费者 goroutinue
完成任务之后通知 main
函数。创建 Waitgroup
的实例 wg
,用于等待所有生产随机数的 goroutine
完成任务。
使用 for
循环创建 100 个 goroutines
。调用 waitgroup
的 wait()
方法等待所有的 goroutines
完成随机数的生成。然后关闭 channel
。当 channel
关闭时,消费者 consume
goroutine
已经将所有的随机数写入文件, 将 true
写入 done
这个 channel 中,这个时候 main
函数解除阻塞并且打印 File written successfully
。