{"id":19990963,"url":"https://github.com/winstonwxj/ExcelCake","last_synced_at":"2025-05-04T10:30:54.505Z","repository":{"id":46784681,"uuid":"167012356","full_name":"winstonwxj/ExcelCake","owner":"winstonwxj","description":"基于Epplus开发的Excel(支持excel 2007及之后版本)通用导入导出类库(支持.net core)。两套实现机制:1.基于特性实现的导入、导出(侵入式)2.基于模板实现的导入、导出(非侵入式)","archived":false,"fork":false,"pushed_at":"2023-07-30T12:40:58.000Z","size":1106,"stargazers_count":61,"open_issues_count":2,"forks_count":19,"subscribers_count":5,"default_branch":"Dev","last_synced_at":"2024-11-13T04:52:51.770Z","etag":null,"topics":["dotnet","dotnet-core2","dotnetcore","epplus","excel","netcore","netcore2"],"latest_commit_sha":null,"homepage":null,"language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"lgpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/winstonwxj.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-01-22T14:55:45.000Z","updated_at":"2024-09-26T01:39:20.000Z","dependencies_parsed_at":"2024-11-13T04:53:04.403Z","dependency_job_id":"09ce7c32-899d-4943-8a6e-a3856812548a","html_url":"https://github.com/winstonwxj/ExcelCake","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/winstonwxj%2FExcelCake","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/winstonwxj%2FExcelCake/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/winstonwxj%2FExcelCake/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/winstonwxj%2FExcelCake/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/winstonwxj","download_url":"https://codeload.github.com/winstonwxj/ExcelCake/tar.gz/refs/heads/Dev","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252320044,"owners_count":21729056,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["dotnet","dotnet-core2","dotnetcore","epplus","excel","netcore","netcore2"],"created_at":"2024-11-13T04:51:33.097Z","updated_at":"2025-05-04T10:30:53.128Z","avatar_url":"https://github.com/winstonwxj.png","language":"C#","funding_links":[],"categories":["C\\#"],"sub_categories":[],"readme":"# ExcelCake\n\n基于 EPPlus 开发的 Excel(支持 excel 2007 及之后版本)通用导入导出类库(支持.net core)。\n\n[![](https://img.shields.io/badge/license-LGPL%20v3-blue.svg)](./LICENSE)\n[![](https://img.shields.io/badge/EPPlus-v4.5.3-brightgreen.svg)](https://github.com/JanKallman/EPPlus)\n![](https://img.shields.io/badge/%E4%BD%9C%E8%80%85-winstonwxj-orange.svg)\n\n## 分支说明\n- master:主分支,不接受合并。\n- Dev:开发分支，接收合并。仅支持.net core 3.1及以上。\n- OldVersion:旧版本分支(.net3.5、.net4.0、.net standard 2.0、.net standard 2.1版本代码)。有需要可以下载此分支。不承诺该分支的维护工作。\n\n## 特性\n\n- 快速实现 Excel 导入导出功能\n- ~~老旧项目(.net 3.5、.net 4.0、.net standard 2.0、.net standard 2.1)支持~~(旧版本代码移步至OldVersion分支)\n- 跨平台支持(.net core 3.1及以上)\n- 多种实现机制:1.基于特性实现的导入导出(侵入式) 2.基于模板实现的导入导出(非侵入式) 3.动态读取配置实现导入导出\n\n## ExcelCake 源码结构\n\n```\n|--ExcelCake                 源码\n|----Intrusive             侵入式部分\n|----NoIntrusive           非侵入式部分\n|----Dynamic               动态配置部分\n|--ExcelCake.Example         Demo\n|--ExcelCake.Test            单元测试\n```\n\n## **作者相关**\n\ngithub: https://github.com/winstonwxj\n\ngitee: \u003chttps://gitee.com/winstonwxj\u003e(不再维护)\n\n## 路线图\n\n- 基于特性数据导出(已实现)\n- 基于特性数据导入(已实现)\n- 基于特性图片导出\n- 基于特性图表导出\n- 基于模板表格导出(已实现)\n- 基于模板表格导入\n- 基于模板图片导出\n- 基于模板图表导出\n- 基于动态配置数据导出\n- 基于动态配置数据导入\n- 基于动态配置图片导出\n- 基于动态配置图表导出\n- 使用其他office open xml实现替代EPPlus\n\n## 模板语法\n### （新版语法）\n**语法可用的最小粒度为配置项，每个配置项使用大括号包裹，各项之间以分号”;”分隔，项和值之间以冒号”:”分隔，忽略大小写。地址配置项为Address时，值以,分隔。**\n- Data:数据源，该项值为数据源中的成员变量，类型必须为属性（含get，set），不支持字段,Type不为Value时可用。如果Value配置字段为数据源直接属性，该项为空。用于Free配置类型(自由格式配置)\n- List:数据源，该项值为数据源中的成员变量，类型必须为属性（含get，set），不支持字段,Type不为Value时可用。如果Value配置字段为数据源集合单个实体的直接属性，该项为空。用于Grid配置类型(表格格式配置)该项值为数据源中的成员变量，类型必须为属性（含get，set），不支持字段,Type不为Value时可用。如果Value配置字段为数据源直接属性，该项为空。\n- @:填充字段名称\nLT:区域左上角单元格坐标,Type不为Value时可用\nRB:区域右下角单元格坐标,Type不为Value时可用\nAddress:指定区域地址，以,号分隔的“区域左上角单元格坐标”和“区域右下角单元格坐标”\n\n**配置示例：**\n1. 自由格式\n{Data:具体对象;LT:区域左上坐标;RB:区域右下坐标}\n或{Data:具体对象;Address:区域左上坐标,区域右下坐标}\n2. 表格格式\n{List:具体对象(集合类型，不支持数组);LT:区域左上坐标;RB:区域右下坐标}\n或{List:具体对象(集合类型，不支持数组);Address:区域左上坐标,区域右下坐标}\n3. 具体填充字段名称\n{@字段名称}\n\n### （旧版语法）\n**语法可用的最小粒度为配置项，每个配置项使用大括号包裹，各项之间以分号”;”分隔，项和值之间以冒号”:”分隔，忽略大小写。**\n- Type:配置类型，包括Free(自由格式配置),Grid(表格格式配置),Value(填充字段配置)\n- DataSource:数据源，该项值为数据源中的成员变量，类型必须为属性（含get，set），不支持字段,Type不为Value时可用。如果Value配置字段为数据源直接属性，该项为空。\n- AddressLeftTop:区域左上角单元格坐标,Type不为Value时可用\n- AddressRightBottom:区域右下角单元格坐标,Type不为Value时可用\n- Field:字段名称，Type为Value时可用\n\n**配置示例：**\n1. 自由格式\n{Type:Free;DataSource:具体对象;AddressLeftTop:区域左上坐标;AddressRightBottom:区域右下坐标}\n2. 表格格式\n{Type:Grid;DataSource:具体对象(集合类型，不支持数组);AddressLeftTop:区域左上坐标;AddressRightBottom:区域右下坐标}\n3. 具体填充字段名称\n{Type:Value;Field:字段名称}\n\n\n## 示例\n\n### 基于特性部分\n#### 实体类定义\n\n```C#\n    [ExportEntity(EnumColor.LightGray,\"用户信息\")]\n    [ImportEntity(titleRowIndex:1,headRowIndex:2,dataRowIndex:4)]\n    public class UserInfo: ExcelBase\n    {\n        [Export(name:\"编号\", index:1,prefix:\"ID:\")]\n        [Import(name:\"编号\",prefix:\"ID:\")]\n        public int ID { set; get; }\n\n        [Export(\"姓名\", 2)]\n        [Import(\"姓名\")]\n        public string Name { set; get; }\n\n        [Export(\"性别\", 3)]\n        [Import(\"性别\")]\n        public string Sex { set; get; }\n\n        [Export(name:\"年龄\", index:4,suffix:\"岁\")]\n        [Import(name:\"年龄\",suffix:\"岁\",dataVerReg: @\"^[1-9]\\d*$\", isRegFailThrowException:false)]\n        public int Age { set; get; }\n\n        [ExportMerge(\"联系方式\")]\n        [Export(\"电子邮件\", 5)]\n        [Import(\"电子邮件\")]\n        public string Email { set; get; }\n\n        [ExportMerge(\"联系方式\")]\n        [Export(\"手机\", 6)]\n        [Import(\"手机\")]\n        public string TelPhone { set; get; }\n\n        public override string ToString()\n        {\n            return string.Format($\"ID:{ID},Name:{Name},Sex:{Sex},Age:{Age},Email:{Email},TelPhone:{TelPhone}\");\n        }\n    }\n\n    [ExportEntity(\"账号信息\")]\n    public class AccountInfo:ExcelBase\n    {\n        [Export(\"编号\", 1)]\n        public int ID { set; get; }\n\n        [Export(\"昵称\", 2)]\n        public string Nickname { set; get; }\n\n        [Export(\"密码\", 3)]\n        public string Password { set; get; }\n\n        [Export(\"旧密码\", 4)]\n        public string OldPassword { set; get; }\n\n        [Export(\"状态\", 5)]\n        public int AccountStatus { set; get; }\n    }\n```\n\n#### 基于特性导出\n```C#\n    private static void IntrusiveExport()\n    {\n        List\u003cUserInfo\u003e list = new List\u003cUserInfo\u003e();\n        string[] sex = new string[] { \"男\", \"女\" };\n        Random random = new Random();\n        for (var i = 0; i \u003c 100; i++)\n        {\n            list.Add(new UserInfo()\n            {\n                ID = i + 1,\n                Name = \"Test\" + (i + 1),\n                Sex = sex[random.Next(2)],\n                Age = random.Next(20, 50),\n                Email = \"test\" + (i + 1) + \"@163.com\",\n                TelPhone = \"1399291\" + random.Next(1000, 9999)\n            });\n        }\n        var temp = list.ExportToExcelBytes(); //导出为byte[]\n\n        var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, \"Export\");\n        if (!Directory.Exists(path))\n        {\n            Directory.CreateDirectory(path);\n        }\n        var exportTitle = \"导出文件\";\n        var filePath = Path.Combine(path, exportTitle + DateTime.Now.Ticks + \".xlsx\");\n        FileInfo file = new FileInfo(filePath);\n        File.WriteAllBytes(file.FullName, temp);\n        Console.WriteLine(\"IntrusiveExport导出完成!\");\n    }\n```\n![avatar](./pics/pic1.PNG)\n\n#### 基于特性多sheet多类型导出\n```C#\n    private static void IntrusiveMultiSheetExport()\n    {\n        Dictionary\u003cstring, IEnumerable\u003cExcelBase\u003e\u003e excelSheets = new Dictionary\u003cstring, IEnumerable\u003cExcelBase\u003e\u003e();\n\n        List\u003cUserInfo\u003e list = new List\u003cUserInfo\u003e();\n        List\u003cAccountInfo\u003e list2 = new List\u003cAccountInfo\u003e();\n        string[] sex = new string[] { \"男\", \"女\" };\n\n        Random random = new Random();\n        for (var i = 0; i \u003c 10000; i++)\n        {\n            list.Add(new UserInfo()\n            {\n                ID = i + 1,\n                Name = \"Test\" + (i + 1),\n                Sex = sex[random.Next(2)],\n                Age = random.Next(20, 50),\n                Email = \"testafsdgfashgawefqwefasdfwefqwefasdggfaw\" + (i + 1) + \"@163.com\",\n                TelPhone = \"1399291\" + random.Next(1000, 9999)\n            });\n            list2.Add(new AccountInfo()\n            {\n                ID = i + 1,\n                Nickname = \"nick\" + (i + 1),\n                Password = random.Next(111111, 999999).ToString(),\n                OldPassword = random.Next(111111, 999999).ToString(),\n                AccountStatus = random.Next(2)\n            });\n        }\n        excelSheets.Add(\"sheet1\", list);\n        excelSheets.Add(\"sheet2\", list2);\n\n\n        var temp = excelSheets.ExportMultiToBytes(); //导出为byte[]\n\n        var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, \"Export\");\n        if (!Directory.Exists(path))\n        {\n            Directory.CreateDirectory(path);\n        }\n        var exportTitle = \"导出文件\";\n        var filePath = Path.Combine(path, exportTitle + DateTime.Now.Ticks + \".xlsx\");\n        FileInfo file = new FileInfo(filePath);\n        File.WriteAllBytes(file.FullName, temp);\n        Console.WriteLine(\"IntrusiveMultiSheetExport导出完成!\");\n    }\n```\n![avatar](./pics/pic3.PNG)\n![avatar](./pics/pic4.PNG)\n\n#### 导入Excel文件结构\n![avatar](./pics/pic7.PNG)\n\n#### 基于特性导入\n```C#\n    private static void IntrusiveImport()\n    {\n        var list = ExcelHelper.GetList\u003cUserInfo\u003e(@\"C:\\Users\\winstonwxj\\Desktop\\导入文件测试.xlsx\");\n        foreach(var item in list)\n        {\n            Console.WriteLine(item);\n        }\n        Console.WriteLine(\"导入完成!\");\n    }\n```\n![avatar](./pics/pic5.PNG)\n\n### 基于模板部分\n#### 模板绘制\n(旧版语法)![avatar](./pics/pic6.PNG)\n(新版语法)![avatar](./pics/pic6new.PNG)\n\n#### 基于模板导出\n```C#\n    private static void NoIntrusiveExport()\n    {\n        var reportInfo = new GradeReportInfo();\n        var exportTitle = \"2018学年期中考试各班成绩汇总\";\n        reportInfo.ReportTitle = exportTitle;\n        var templateFileName = \"复杂格式测试模板.xlsx\";\n\n        #region 构造数据\n        var list1 = new List\u003cClassInfo\u003e();\n        list1.Add(new ClassInfo()\n        {\n            ClassName = \"班级1\",\n            PassCountSubject1 = 20,\n            PassCountSubject2 = 15,\n            PassCountSubject3 = 10,\n            PassCountSubject4 = 13,\n            PassCountSubject5 = 25\n        });\n        list1.Add(new ClassInfo()\n        {\n            ClassName = \"班级2\",\n            PassCountSubject1 = 19,\n            PassCountSubject2 = 20,\n            PassCountSubject3 = 17,\n            PassCountSubject4 = 11,\n            PassCountSubject5 = 19\n        });\n        list1.Add(new ClassInfo()\n        {\n            ClassName = \"班级3\",\n            PassCountSubject1 = 17,\n            PassCountSubject2 = 23,\n            PassCountSubject3 = 12,\n            PassCountSubject4 = 16,\n            PassCountSubject5 = 21\n        });\n        list1.Add(new ClassInfo()\n        {\n            ClassName = \"班级4\",\n            PassCountSubject1 = 23,\n            PassCountSubject2 = 17,\n            PassCountSubject3 = 16,\n            PassCountSubject4 = 14,\n            PassCountSubject5 = 22\n        });\n        list1.Add(new ClassInfo()\n        {\n            ClassName = \"班级5\",\n            PassCountSubject1 = 23,\n            PassCountSubject2 = 17,\n            PassCountSubject3 = 16,\n            PassCountSubject4 = 14,\n            PassCountSubject5 = 22\n        });\n        var list2 = new List\u003cClassInfo\u003e();\n        list2.Add(new ClassInfo()\n        {\n            ClassName = \"班级1\",\n            ScoreAvgSubject1 = 81.25,\n            ScoreAvgSubject2 = 65.75,\n            ScoreAvgSubject3 = 79.05,\n            ScoreAvgSubject4 = 59.15,\n            ScoreAvgSubject5 = 83.05\n        });\n        list2.Add(new ClassInfo()\n        {\n            ClassName = \"班级2\",\n            ScoreAvgSubject1 = 79.25,\n            ScoreAvgSubject2 = 63.75,\n            ScoreAvgSubject3 = 71.05,\n            ScoreAvgSubject4 = 62.15,\n            ScoreAvgSubject5 = 85\n        });\n        list2.Add(new ClassInfo()\n        {\n            ClassName = \"班级3\",\n            ScoreAvgSubject1 = 71.5,\n            ScoreAvgSubject2 = 63.25,\n            ScoreAvgSubject3 = 75.25,\n            ScoreAvgSubject4 = 61.25,\n            ScoreAvgSubject5 = 80.05\n        });\n        list2.Add(new ClassInfo()\n        {\n            ClassName = \"班级4\",\n            ScoreAvgSubject1 = 84.5,\n            ScoreAvgSubject2 = 61.25,\n            ScoreAvgSubject3 = 75.25,\n            ScoreAvgSubject4 = 57.35,\n            ScoreAvgSubject5 = 81.5\n        });\n        var list3 = new List\u003cClassInfo\u003e();\n        list3.Add(new ClassInfo()\n        {\n            ClassName = \"班级1\",\n            ScoreTotalMax = 432,\n            ScoreTotalAvg = 315.25,\n            ScoreTotalPassRate = 47.25\n        });\n        list3.Add(new ClassInfo()\n        {\n            ClassName = \"班级2\",\n            ScoreTotalMax = 466.5,\n            ScoreTotalAvg = 330.75,\n            ScoreTotalPassRate = 44.75\n        });\n        list3.Add(new ClassInfo()\n        {\n            ClassName = \"班级3\",\n            ScoreTotalMax = 422,\n            ScoreTotalAvg = 345.25,\n            ScoreTotalPassRate = 51.05\n        });\n        list3.Add(new ClassInfo()\n        {\n            ClassName = \"班级4\",\n            ScoreTotalMax = 444,\n            ScoreTotalAvg = 335.25,\n            ScoreTotalPassRate = 46.15\n        });\n        #endregion\n\n        reportInfo.List1 = list1;\n        reportInfo.List2 = list2;\n        reportInfo.List3 = list3;\n\n        ExcelTemplate customTemplate = new ExcelTemplate(templateFileName);\n        var byteInfo = customTemplate.ExportToBytes(reportInfo, \"Template/复杂格式测试模板.xlsx\");\n        var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, \"Export\");\n        if (!Directory.Exists(path))\n        {\n            Directory.CreateDirectory(path);\n        }\n        var filePath = Path.Combine(path, exportTitle + DateTime.Now.Ticks + \".xlsx\");\n        FileInfo file = new FileInfo(filePath);\n        File.WriteAllBytes(file.FullName, byteInfo);\n        Console.WriteLine(\"NoIntrusiveExport导出完成!\");\n    }\n```\n![avatar](./pics/pic2.PNG)\n\n## 文档\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwinstonwxj%2FExcelCake","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwinstonwxj%2FExcelCake","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwinstonwxj%2FExcelCake/lists"}