// 需求------将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 + "寫入完畢")
}