并发写文件:

注意点:

协程数不宜过多,避免协程间的频繁切换影响性能(根据cpu核数而定)
bufio 通过 flush 操作将缓冲写入真实的文件的,所以一定要在关闭文件之前先flush,否则会造成数据丢失的情况
package main

import (
	"bufio"
	"fmt"
	"os"
	"runtime"
	"runtime/debug"
	"sync"
)

// bufio库的流式处理	如果文件较小,使用ioutil也不失为一种方法
func WriteDataToTxt() {
	txtFile, err := os.OpenFile("55555.txt", os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0777) // O_TRUNC 清空重写
	if err != nil {
		fmt.Println("WriteDataToTxt os.OpenFile() err:", err)
		return
	}
    defer txtFile.Close()
	// txtFile.WriteString() // os操作文件-效率低

	bufWriter := bufio.NewWriter(txtFile)
	var wg sync.WaitGroup
	limitChan := make(chan struct{}, runtime.GOMAXPROCS(runtime.NumCPU())) // 最大并发协程数
	var mutex sync.Mutex

	for i := 0; i < 10000; i++ { // 写1w行测试
		limitChan <- struct{}{}
		wg.Add(1)

		go func(j int) {
			defer func() {
				if e := recover(); e != nil {
					fmt.Printf("WriteDataToTxt panic: %v,stack: %s\n", e, debug.Stack())
					// return
				}

				wg.Done()
				<-limitChan
			}()

			// 模拟业务逻辑:先整合所有数据,然后再统一写WriteString()
			strId := fmt.Sprintf("%v", j)
			strName := fmt.Sprintf(" user_%v", j)
			strScore := fmt.Sprintf(" %d", j*10)

			mutex.Lock() // 要加锁/解锁,否则 bufWriter.WriteString 写入数据有问题
			_, err := bufWriter.WriteString(strId + strName + strScore + "\n")
			if err != nil {
				fmt.Printf("WriteDataToTxt WriteString err: %v\n", err)
				return
			}
			mutex.Unlock()

			// bufWriter.Flush() // 刷入磁盘(错误示例:WriteDataToTxt err: short write,short write;因为循环太快,有时写入的数据量太小了)
		}(i)
	}
	wg.Wait()
	bufWriter.Flush() // 刷入磁盘(正确示例,bufio 通过 flush 操作将缓冲写入真实的文件的,所以一定要在关闭文件之前先flush,否则会造成数据丢失的情况)
}

报错: 

读文件:

注意点:

ReadSliceReadLineReadBytesReadStringReadLine\n\r\nReadLine
package main

import (
	"bufio"
	"fmt"
	"io"
	"os"
)

// 读文件
func ReadDataFromTxt() {
	txtFile, err := os.OpenFile("55555.txt", os.O_RDONLY, 0777) // O_TRUNC 清空重写
	if err != nil {
		fmt.Println("WriteDataToTxt os.OpenFile() err:", err)
		return
	}
	defer txtFile.Close()

	bufReader := bufio.NewReader(txtFile)

	for {
		data, _, err := bufReader.ReadLine() // 读一行日志
		if err == io.EOF {                   // 如果列表读完了,退出
			fmt.Println("数据读完了~")
			break
		}

		fmt.Println("data: ", string(data))
	}
	return
}