帮朋友做 excel 的简单处理。原本是 python 栈,心想使用省事就像打包成 exe 文件,python 打包的 exe 文件又太大,而且会有各种奇奇怪怪的问题。刚好最近在学 golang,就用 golang 在写代码,不过遇到了 Goroutine 和 Channel 配合使用的问题。
问题的大致是这样的,先找出所有的符合条件的 Excel 文件,放入一个 chanfileChan
中,然后通过读取这个 chan 中的数据,使用 Goroutine 调用utlis.ReadExcelFile
的方法将传入的文件进行分析,只对需要的处理的行进行处理,并用一个 chanResultChan
去接受,最后再将读取到的结果进行处理。但是对ResultChan
进行处理之后就会报死锁的错误,我怎么样都不能定位到原因。请各位好哥哥帮帮我。
代码如下
main.go
package main
import (
utils "excelmaker/src/Utils"
"fmt"
"log"
"os"
"path/filepath"
"strings"
"sync"
)
func main() {
pwd, _ := os.Getwd() // 找到本地路径
filenamePaths, err := filepath.Glob(filepath.Join(pwd, "*")) //获取本地目录下所有文件
if err != nil {
log.Fatal(err)
}
fileChan := make(chan string, 5)
for _, filePathName := range filenamePaths {
fileExt := filepath.Ext(filePathName)
fileName := filepath.Base(filePathName)
if fileExt == ".xlsx" && strings.Contains(fileName, "工资表") {
fmt.Println(filePathName)
fileChan <- filePathName
}
}
totalFileNum := len(fileChan)
wg := sync.WaitGroup{}
wg.Add(totalFileNum)
for filePathName := range fileChan {
go utils.ReadExcelFile(filePathName, &wg)
}
go utils.MakeTotalExcel() //会出现死锁
wg.Wait()
}
Utils/utils.go
package utils
import (
"fmt"
"strconv"
"strings"
"sync"
"github.com/360EntSecGroup-Skylar/excelize/v2"
)
type ExcelData struct {
Name string
Salar int
Company string
}
var ResultChan = make(chan *ExcelData, 10)
const SalaryTable = "工资表"
func ReadExcelFile(filePathName string, wg *sync.WaitGroup) {
// func ReadExcelFile(filePathName string) {
f, err := excelize.OpenFile(filePathName)
if err != nil {
fmt.Println(err)
return
}
var company string
if strings.Contains(filePathName, "头疗") {
company = "头疗店"
} else if strings.Contains(filePathName, "城东") {
company = "城东店"
} else if strings.Contains(filePathName, "熹 SPA") {
company = "熹 SPA 店"
} else if strings.Contains(filePathName, "置地") {
company = "置地店"
} else {
company = "东方丽景店"
}
result, _ := f.SearchSheet(SalaryTable, "实发工资", false)
salaryColIndex, _, _ := excelize.CellNameToCoordinates(result[0])
rows, err := f.Rows(SalaryTable)
if err != nil {
fmt.Println(err)
return
}
for rows.Next() {
row, err := rows.Columns()
if err != nil {
fmt.Println(err)
return
}
if len(row) != 0 {
var stringNotAnalysisList = []string{"", "姓名", "合计"}
if ok, _ := Contain(row[0], stringNotAnalysisList); ok {
continue
} else {
salary, _ := strconv.Atoi(row[salaryColIndex-1])
tempData := ExcelData{
Name: row[0],
Salar: salary,
Company: company,
}
ResultChan <- &tempData
}
}
}
wg.Done()
}
func MakeTotalExcel() {
resultMap := make(map[string]map[string]int)
companyList := []string{"姓名"}
for v := range ResultChan {
// fmt.Println(v.Name)
if ok, _ := Contain(v.Name, resultMap); !ok {
resultMap[v.Name] = make(map[string]int)
}
resultMap[v.Name][v.Company] = v.Salar
if ok, _ := Contain(v.Company, companyList); !ok {
companyList = append(companyList, v.Company)
}
}
fmt.Println(companyList)
fmt.Println(resultMap)
}
Utils/commont_utils.go
package utils
import (
"errors"
"reflect"
)
// 判断 obj 是否在 target 中,target 支持的类型 arrary,slice,map
func Contain(obj interface{}, target interface{}) (bool, error) {
targetValue := reflect.ValueOf(target)
switch reflect.TypeOf(target).Kind() {
case reflect.Slice, reflect.Array:
for i := 0; i < targetValue.Len(); i++ {
if targetValue.Index(i).Interface() == obj {
return true, nil
}
}
case reflect.Map:
if targetValue.MapIndex(reflect.ValueOf(obj)).IsValid() {
return true, nil
}
}
return false, errors.New("not in array")
}
这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。
V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。
V2EX is a community of developers, designers and creative people.