并发写文件:
注意点:
- runtime.GOMAXPROCS(runtime.NumCPU()) 限制并发写操作的协程数:
协程数不宜过多,避免协程间的频繁切换影响性能(根据cpu核数而定)
- WriteString()操作要加锁,否则最终写入数据有问题(乱码等...)
- 最后记得Flush()一下:
bufio 通过 flush 操作将缓冲写入真实的文件的,所以一定要在关闭文件之前先flush,否则会造成数据丢失的情况
packagemainimport ( "bufio""fmt""os""runtime""runtime/debug""sync") // bufio库的流式处理 如果文件较小,使用ioutil也不失为一种方法funcWriteDataToTxt() { txtFile, err :=os.OpenFile("55555.txt", os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0777) // O_TRUNC 清空重写iferr!=nil { fmt.Println("WriteDataToTxt os.OpenFile() err:", err) return } defertxtFile.Close() // txtFile.WriteString() // os操作文件-效率低bufWriter :=bufio.NewWriter(txtFile) varwgsync.WaitGrouplimitChan :=make(chanstruct{}, runtime.GOMAXPROCS(runtime.NumCPU())) // 最大并发协程数varmutexsync.Mutexfori :=0; i<10000; i++ { // 写1w行测试limitChan<-struct{}{} wg.Add(1) gofunc(jint) { deferfunc() { ife :=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") iferr!=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,否则会造成数据丢失的情况)}
报错:
编辑
读文件:
注意点:
- 读取文件中一行内容时,
ReadSlice
和ReadLine
性能优于ReadBytes
和ReadString
,但由于ReadLine
对换行的处理更加全面(兼容\n
和\r\n
换行),因此,实际开发过程中,建议使用ReadLine
函数。 - 关于os.File、bufio、ioutil 写文件的性能比较,参考:
https://segmentfault.com/a/1190000023691973
packagemainimport ( "bufio""fmt""io""os") // 读文件funcReadDataFromTxt() { txtFile, err :=os.OpenFile("55555.txt", os.O_RDONLY, 0777) // O_TRUNC 清空重写iferr!=nil { fmt.Println("WriteDataToTxt os.OpenFile() err:", err) return } defertxtFile.Close() bufReader :=bufio.NewReader(txtFile) for { data, _, err :=bufReader.ReadLine() // 读一行日志iferr==io.EOF { // 如果列表读完了,退出fmt.Println("数据读完了~") break } fmt.Println("data: ", string(data)) } return}