// 需求------将TXT文件中的数据按照不同省市放进不同的省市文件中。
// 面向过程思路:创建34个文件,然后读取文件逐行将数据放进通道内,1协程从通道内读取数据,分析是属于哪个省市然后写入文件中。这个是面向过程的写法。
// 弊端:可能同时有两个协程共同写入一个文件 造成数据缺失
// 问题:1.如何判断是否读取结束,关闭协程,select 两个channel一个循环数据一个结束读取2.加锁防止两个协程同时写入每个文件
// 面向对象思路:创建34个文件,34个通道,然后读取文件逐行分析是哪个省市然后放进对应的通道中,(34个协程从34个通道中读取数据分析省市写入对应文件中,这么写和面向过程就一样了,没有意义)应该将通道和文件绑定在一个对象内,接收端一接收数据立即写入绑定的文件 还分析个屁呀
// 优点:34个协程一个文件一个协程 不会有两个协程写入一个文件的错误,
// 问题:1.如何判断这个省的协程是否结束 wg
// 面向思想主要是将文件和通道绑定 做结构体 将结构体作为参数传递
// 最后阻塞wg 和 关闭通道 总是忘记
package main
import (
"bufio"
"fmt"
"io"
"os"
"strconv"
"strings"
"sync"
)
type Provice struct {
// 省份证前两位
Id int
// 省的名称
Name string
// 对应省的文件
FileName *os.File
// 对应省的通道
ChanData chan string
}
var wg sync.WaitGroup
func main() {
ps := []string{
"北京11", "天津12", "河北13", "内蒙古15", "上海31", "湖北42", "湖南43",
"广西45", "海南46", "四川51", "贵州52", "云南53", "西藏54", "重庆55",
"陕西61", "甘肃62", "青海63", "宁夏64", "新疆65", "山西14", "辽宁21",
"吉林22", "黑龙江23", "江苏32", "浙江33", "河南41", "澳门82", "台湾83",
"香港81",
}
proviceMap := make(map[int]*Provice, 4096) // 这 里是指针 对象作为参数值 一般都是指针
for _, v := range ps {
name := v[:len(v)-2]
idstr := v[len(v)-2:]
id, _ := strconv.Atoi(idstr)
provice := Provice{Id: id, Name: name}
file, err := os.OpenFile("./info/"+name+".txt", os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0666)
if err != nil {
panic(name + "文件创建失败")
}
defer file.Close()
provice.FileName = file
provice.ChanData = make(chan string, 4096)
proviceMap[id] = &provice
fmt.Println(name + "对象创建完成")
}
// 创建34个协程 监听写入文件
for _, v := range proviceMap {
wg.Add(1)
go wirteData(v)
}
// 开始读数据
file, err := os.Open("info.txt")
if err != nil {
panic("打开文件错误")
}
defer file.Close()
bufioReader := bufio.NewReader(file)
for {
line, _, err := bufioReader.ReadLine()
if err == io.EOF {
fmt.Println("读取原始文件数据完毕")
// 读取完毕后 循环关闭通道
for _, v := range proviceMap {
close(v.ChanData)
}
break
}
lineStr := string(line) // 转化字符串
fmt.Println(lineStr)
lineArr := strings.Split(lineStr, ",") // 按,分割
idstr := lineArr[1][0:2]
id, _ := strconv.Atoi(idstr) // 获取第二个数组的前二位
if provice, ok := proviceMap[id]; ok {
provice.ChanData <- lineStr
}
}
wg.Wait()
fmt.Println("操作完毕")
}
// 写入数据
func wirteData(provice *Provice) {
for data := range provice.ChanData {
provice.FileName.Write([]byte(data + "\n"))
}
wg.Done()
fmt.Println(provice.Name + "写入完毕")
}