目录
- 练习要求:
- 考察点:
- 编码:
- readme.md
- 附:使用golang导出csv数据并解决数据乱码问题
- csv 格式
- 实现方式
- golang实现csv数据写文件
- golang实现web导出csv数据
- 总结
练习要求:
写一个小程序解析data.csv,要求实现如下功能:
- 接收姓名作为参数。
- 根据姓名查找出对应员工的工时信息,并将 日期、上班、下班、工时 打印到标准输出。
- 将上一条输出的内容保存到json文件,使用姓名.json作为文件名
- 根据上条中生成的json文件,计算出该员工的月总工时、每周的平均工时。
考察点:
- 结构体定义
- 字符串拼接
- 类型转换
- 编码转换
- 命令行参数解析
- 文件读取
- json库使用
编码:
package main import ( "bufio" "encoding/json" "errors" "flag" "fmt" "io" "os" "strconv" "strings" "github.com/axgle/mahonia" ) //给 fmt.println 起一个短的别名。 var p = fmt.println //定义一个全局变量 一个月上班加休息总天数 var galldays float64 = 0 //定义一个全局变量 考勤异常的天数 var gabnormaldays int = 0 //上班信息 type workinfo struct { workdate string //上班日期 starttime string //上班打卡时间 endtime string //下班打卡时间 laborhour string //当天工时 } //考勤异常信息 type workabnormalinfo struct { workdate string //上班日期 normalinfo string //异常信息 } /** * @brief 把当前字符串按照指定方式进行编码 * @param[in] src 待进行转码的字符串 * @param[in] srccode 字符串当前编码 * @param[in] tagcode 要转换的编码 * @return 进行转换后的字符串 */ func converttostring(src string, srccode string, tagcode string) (string, error) { if len(src) == 0 || len(srccode) == 0 || len(tagcode) == 0 { return "", errors.new("input arguments error") } srccoder := mahonia.newdecoder(srccode) srcresult := srccoder.convertstring(src) tagcoder := mahonia.newdecoder(tagcode) _, cdata, _ := tagcoder.translate([]byte(srcresult), true) result := string(cdata) return result, nil } /** * @brief 写入数据到指定名字的文件中 * @param[in] buf 待写入的数据内容 * @param[in] name 文件名字 * @return 成功返回nil 失败返回error 错误信息 */ func writefile(name string, buf string) error { if len(name) == 0 || len(buf) == 0 { return errors.new("input arguments error") } fout, err := os.openfile(name, os.o_create|os.o_rdwr, 0666) defer fout.close() if err != nil { return err } //写入到本地文件中 fout.writestring(buf) return nil } /** * @brief 读取文件 * @param[in] name 文件名(可以加路径) * @return 成功返回 文件内容,失败返回error 错误信息 */ func readfile(name string) ([]byte, error) { if len(name) == 0 { return nil, errors.new("input arguments error") } //打开本地文件 读取出全部数据 fin, err := os.open(name) defer fin.close() if err != nil { return nil, errors.new("close error") } buf_len, _ := fin.seek(0, os.seek_end) fin.seek(0, os.seek_set) buf := make([]byte, buf_len) fin.read(buf) return buf, nil } /** * @brief 读取csv文件并打印指定员工信息 * @param[in] csvname csv文件名(可以加路径) * @param[in] employeename 员工名字 * @return 成功返回 员工结构体信息,失败返回error 错误信息 */ func readcsvfile(csvname string, employeename string) ([]workinfo, error) { if len(csvname) == 0 || len(employeename) == 0 { return nil, errors.new("error: input arguments error") } var workinfoset []workinfo var abnormalset []workabnormalinfo var isexistname bool var daycount float64 = 0 var isnormal string var isnormalflag bool var index int = 0 var indexworkdate int var indexstarttime int var indexendtime int var indexlaborhour int var indexnormalinfo int var indexisnormal int var i int = 0 f, err := os.open(csvname) if err != nil { return nil, err } defer f.close() rd := bufio.newreader(f) for { gbk_line, err := rd.readstring('\n') //以'\n'为结束符读入一行 if err != nil || io.eof == err { break } //p("gbk:", gbk_line) //把每一行gbk格式的字符串 转换为 utf-8格式字符串 utf8_line, _ := converttostring(gbk_line, "gbk", "utf-8") //对第一行进行处理 if i == 0 { i = 1 //保证 只有第一行被处理 p("utf8:", utf8_line) first_line := strings.split(utf8_line, ",") for _, val := range first_line { if val == "日期" { indexworkdate = index } if val == "上班" { indexstarttime = index } if val == "下班" { indexendtime = index } if val == "工时" { indexlaborhour = index } if val == "是否有考勤异常" { indexisnormal = index } if val == "工时异常" { indexnormalinfo = index } index++ } } if strings.contains(utf8_line, employeename) { //把存在员工标记为true isexistname = true split_line := strings.split(utf8_line, ",") person_temp := workinfo{split_line[indexworkdate], split_line[indexstarttime], split_line[indexendtime], split_line[indexlaborhour], } //考勤表天数加1 daycount++ isnormal = split_line[indexisnormal] //统计打卡异常的信息 if isnormal == "是" { ainfo := workabnormalinfo{split_line[indexworkdate], split_line[indexnormalinfo]} abnormalset = append(abnormalset, ainfo) gabnormaldays++ isnormalflag = true } workinfoset = append(workinfoset, person_temp) } } //统计考勤表里所有天数 galldays = daycount //对于不存在指定员工名字 的处理 if !isexistname { p("\nremind: there is no employee is csv file!\n") os.exit(1) } //显示员工所有考勤信息 p("\n员工姓名:", employeename) p("\n全部考勤信息:") for _, temp := range workinfoset { fmt.printf( "日期:%s ,上班:%s,下班:%s,工时:%s\n", temp.workdate, temp.starttime, temp.endtime, temp.laborhour, ) } //显示员工打卡异常信息 if isnormalflag { p("\n异常考勤信息:") for _, val := range abnormalset { fmt.printf("日期:%s , 异常信息:%s\n", val.workdate, val.normalinfo) } p("温馨提示:考勤出现异常信息,请及时给助理说明情况~_~\n") } return workinfoset, nil } /** * @brief 写入json文件 * @param[in] employeename 员工名字 * @param[in] workinfoset 员工结构体信息 * @return 成功返回 nil,失败返回error 错误信息 */ func writejsonfile(employeename string, workinfoset []workinfo) error { if len(employeename) == 0 || workinfoset == nil { return errors.new("error: input arguments error") } //把输出内容写入name.json文件中 filename := fmt.sprintf("%s%s", employeename, ".json") str, _ := json.marshal(workinfoset) err := writefile(string(str), filename) if err != nil { return err } return nil } /** * @brief 读取json文件 * @param[in] employeename 员工名字 * @return 成功返回 nil,失败返回error 错误信息 */ func readjsonfile(employeename string) error { if len(employeename) == 0 { return errors.new("error: input arguments error") } var workinfoset []workinfo filename := fmt.sprintf("%s%s", employeename, ".json") readjsonbuf, err := readfile(filename) if err != nil { p(err.error()) return err } var sumhour float64 = 0.0 var daycount float64 = 0 var weekcounts float64 = 0.0 var averageweekhour float64 = 0.0 json.unmarshal(readjsonbuf, &workinfoset) for _, one_work := range workinfoset { //去掉打卡异常情况和周六末情况 (如果周六末加班 数据依然计算进入总工时) if one_work.starttime == "" || one_work.endtime == "" { continue } one_day_hour, _ := strconv.parsefloat(one_work.laborhour, 64) sumhour += one_day_hour daycount++ } fmt.printf("根据json文件计算工时,考勤正常天数:%2.0f, 异常天数:%d\n", daycount, gabnormaldays) weekcounts = galldays / 7 averageweekhour = sumhour / weekcounts //p("考勤表总天数:", galldays, ",共多少周:", week_counts) fmt.printf("月总工时:%.4f 每周的平均工时:%.4f\n\n", sumhour, averageweekhour) return nil } func main() { args := os.args input := flag.string("i", "查无此人", "input employee name") path := flag.string("p", "./data.csv", "input csv file path") flag.parse() if len(args) == 1 { fmt.println("./main: missing operand") fmt.println("try `./main -h' or './main --help' for more information.") return } var csvname string = *path var employeename string = *input //读取csv文件并打印指定员工信息 workinfoset, err := readcsvfile(csvname, employeename) if err != nil { p(err.error()) return } //把指定员工信息写入json文件 err = writejsonfile(employeename, workinfoset) if err != nil { p(err.error()) return } //读取json文件并计算指定员工总工时和平均工时 err = readjsonfile(employeename) if err != nil { p(err.error()) return } }
readme.md
– usage: analysis csv file command [arguments] …
– the commands are:
– -h , –help cmd help.– the commands are:
– -i input employee name.– the commands are:
– -p input csv file path.-当文件中不存在指定员工名字时,返回提醒信息
-参考链接:
– golang gbk转utf-8 参考链接:https://blog.csdn.net/qq_33285730/article/details/73239263
– golang 文件按行读取:https://studygolang.com/articles/282
– golang strings包方法:https://studygolang.com/articles/2881
附:使用golang导出csv数据并解决数据乱码问题
在日常开发中,针对数据导出,我们可以导出excel格式,但是如果是针对大数据量的导出,直接导出为excel格式可能需要占用大量内存,且导出速度很慢。这个时候我们就需要导出为csv格式。
csv 格式
csv本质上是文本文件,该文件有以下要求:
- 列之间用逗号分隔,行之间用换行分隔
- 单元格如果有逗号、引号之类的字符,该单元格需要使用双引号括起来
- 如果内容包含中文,直接输出可能会乱码
实现方式
golang 官方有csv的库,可以很容易的实现csv数据的写入。
golang实现csv数据写文件
func main() { f, err := os.create("data.csv") if err != nil { panic(err) } defer f.close() f.writestring("\xef\xbb\xbf") // 写入utf-8 bom,避免使用microsoft excel打开乱码 writer := csv.newwriter(f) writer.write([]string{"编号", "姓名", "年龄"}) writer.write([]string{"1", "张三", "23"}) writer.write([]string{"2", "李四", "24"}) writer.write([]string{"3", "王五", "25"}) writer.write([]string{"4", "赵六", "26"}) writer.flush() // 此时才会将缓冲区数据写入 }
golang实现web导出csv数据
此处以gin框架为例,如果用的go官方web库,其实差不多是一样的:
func exportcsv(c *gin.context) { bytesbuffer := &bytes.buffer{} bytesbuffer.writestring("\xef\xbb\xbf") // 写入utf-8 bom,避免使用microsoft excel打开乱码 writer := csv.newwriter(bytesbuffer) writer.write([]string{"编号", "姓名", "年龄"}) writer.write([]string{"1", "张三", "23"}) writer.write([]string{"2", "李四", "24"}) writer.write([]string{"3", "王五", "25"}) writer.write([]string{"4", "赵六", "26"}) writer.flush() // 此时才会将缓冲区数据写入 // 设置下载的文件名 c.writer.header().set("content-disposition", "attachment;filename=data.csv") // 设置文件类型以及输出数据 c.data(http.statusok, "text/csv", bytesbuffer.bytes()) return }
总结
到此这篇关于golang如何操作csv文件的文章就介绍到这了,更多相关golang操作csv文件内容请搜索www.887551.com以前的文章或继续浏览下面的相关文章希望大家以后多多支持www.887551.com!
黄山市民网:https://www.huangshanshimin.com/