golang如何操作csv文件详解
知识点掌握了,还需要不断练习才能熟练运用。下面golang学习网给大家带来一个Golang开发实战,手把手教大家学习《golang如何操作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的知识介绍,希望对你的学习有所帮助!若是受益匪浅,那就动动鼠标收藏这篇《golang如何操作csv文件详解》文章吧,也可关注golang学习网公众号了解相关技术文章。

- 上一篇
- GoLang中Json Tag用法实例总结

- 下一篇
- 解析Golang中的GoPath和GoModule
-
- 有魅力的网络
- 很棒,一直没懂这个问题,但其实工作中常常有遇到...不过今天到这,看完之后很有帮助,总算是懂了,感谢师傅分享技术贴!
- 2023-02-12 00:15:37
-
- 甜美的睫毛膏
- 这篇技术文章出现的刚刚好,好细啊,真优秀,mark,关注大佬了!希望大佬能多写Golang相关的文章。
- 2023-02-10 03:22:27
-
- 怕孤单的墨镜
- 这篇博文出现的刚刚好,博主加油!
- 2023-02-09 14:22:47
-
- 爱撒娇的吐司
- 细节满满,收藏了,感谢大佬的这篇博文,我会继续支持!
- 2023-01-22 05:16:49
-
- Golang · Go教程 | 4小时前 |
- DebianOpenSSL安装失败的终极解决方案
- 501浏览 收藏
-
- Golang · Go教程 | 5小时前 |
- Debian数据快速提取技巧
- 216浏览 收藏
-
- Golang · Go教程 | 8小时前 |
- Debian系统JS依赖管理终极攻略
- 218浏览 收藏
-
- Golang · Go教程 | 10小时前 |
- Debian上Hadoop作业调度实用技巧
- 100浏览 收藏
-
- Golang · Go教程 | 10小时前 |
- Go语言闭包误区与匿名函数深度解析
- 222浏览 收藏
-
- Golang · Go教程 | 10小时前 |
- Debian系统安全回收数据的正确攻略
- 111浏览 收藏
-
- Golang · Go教程 | 12小时前 |
- Debian高效fetch技巧与使用攻略
- 125浏览 收藏
-
- Golang · Go教程 | 18小时前 |
- Debian邮件服务器升级维护攻略
- 474浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 542次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 508次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 497次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 484次学习
-
- 笔灵AI生成答辩PPT
- 探索笔灵AI生成答辩PPT的强大功能,快速制作高质量答辩PPT。精准内容提取、多样模板匹配、数据可视化、配套自述稿生成,让您的学术和职场展示更加专业与高效。
- 14次使用
-
- 知网AIGC检测服务系统
- 知网AIGC检测服务系统,专注于检测学术文本中的疑似AI生成内容。依托知网海量高质量文献资源,结合先进的“知识增强AIGC检测技术”,系统能够从语言模式和语义逻辑两方面精准识别AI生成内容,适用于学术研究、教育和企业领域,确保文本的真实性和原创性。
- 23次使用
-
- AIGC检测-Aibiye
- AIbiye官网推出的AIGC检测服务,专注于检测ChatGPT、Gemini、Claude等AIGC工具生成的文本,帮助用户确保论文的原创性和学术规范。支持txt和doc(x)格式,检测范围为论文正文,提供高准确性和便捷的用户体验。
- 30次使用
-
- 易笔AI论文
- 易笔AI论文平台提供自动写作、格式校对、查重检测等功能,支持多种学术领域的论文生成。价格优惠,界面友好,操作简便,适用于学术研究者、学生及论文辅导机构。
- 40次使用
-
- 笔启AI论文写作平台
- 笔启AI论文写作平台提供多类型论文生成服务,支持多语言写作,满足学术研究者、学生和职场人士的需求。平台采用AI 4.0版本,确保论文质量和原创性,并提供查重保障和隐私保护。
- 35次使用
-
- go按行读取文件的三种实现方式汇总
- 2022-12-29 400浏览
-
- Go 语言实现 HTTP 文件上传和下载
- 2023-01-19 235浏览
-
- golang是否文件File自带有io.Writer的属性?
- 2023-01-26 359浏览
-
- Golang文件读写操作详情
- 2022-12-27 426浏览
-
- go压缩解压zip文件源码示例
- 2022-12-27 495浏览