马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有帐号?注册帐号
x
【前言】
之前接手一个同事的代码时,发现其中有个项目用到了Excle,随后就产生了兴趣,想把这个常用的办公软件应用Unity,就利用空余时间研究了几天。之前在技术群看到有人问过Excle如何读写,然后加了他好友后,他发了个不全的Excle插件给我,然后我发现很多报错,就自己在百度娘哪里找了一个完整功能的Excle插件,归根到底,他的底层逻辑也是基于NPOI的Dll文件来实现数据读写,所以我就总结了前任程序的代码和网上的一些案例,写了一个关于Excle读写的功能。
多得也不说了,看一下我总结的成果吧。
【准备工作】
要准备NPOI的Dll文件,来为Unity做程序集调用。Dll文件我放入底下的码云链接,可以在最后的话中点击下载。
【进入开发环节】
1.新建一个结构体,作为保存玩家信息类型,注意要用[Serializable],方便能序列化到Inspector面板
- [
- public struct PData
- {
- public string name_use;//用户名
- public string number_phone;//手机号
- public string number_IDCard;//身份证号码
- public string password;//用户密码
- }
2.Start方创建放置Json文件的目录,以及我们设置的PData结构体数据写入到Json中,然后用文件流写入Excle表(其实这里多写了一步Json的读写如果不需要Json保存各玩家数据的话,直接用结构体写入Excle)
- void Start()
- {
- path_pData = Application.streamingAssetsPath +\\\"PData.xlsx\\\";//Excle表和位置Application.dataPath不能在创建成员变量时使用
- try
- {
- string path_json = Application.dataPath + \\\"Json\\\";
- if (Directory.Exists(path_json) == false)
- {
- Directory.CreateDirectory(path_json);
- print(\\\"creatPath\\\");
- }
- }
- catch (Exception ex)
- {
- print(\\\"创建文件异常:\\\" + ex);
- //throw;
- }
- try
- {
- //print(pDatas.Length);
- for (int i = 0; i < pDatas.Length; i++)//将PData所填写的数据先写入Json然后用文件流写入Excle表(如果要改写 pData现有的数据,要删除对应的json文件增加长度则不用),其实这里没必要,只是我多写了一步Json的读写
- {
- if (File.Exists(Application.dataPath + \\\"/Json/user\\\" + i + \\\".json\\\") == false)
- {
- FileStream fs = new FileStream(Application.dataPath + \\\"Json/user\\\" + i + \\\".json\\\" FileMode.Create);//创建json
- byte[] bytes_write = System.Text.Encoding.GetEncoding(\\\"GB2312\\\").GetBytes(JsonMapper.ToJson(pDatas[i]));
- fs.Write(bytes_write 0 bytes_write.Length);
- fs.Close();
- fs.Dispose();//文件流销毁
- print(\\\"creatJson\\\");
- }
- }
- }
- catch (Exception ex)
- {
- print(\\\"Json创建异常:\\\" + ex);
- //throw;
- }
- WriteExicle();//写入exicle表
- ExicleToDataTable(\\\"Sheet1\\\"true);//从exicle写入系统表中
- }
3.将结构体数据写入Excle表格:遍历Json文件夹的文件然后将所有保存不同玩家的信息反序列化成PData结构体(绕了一圈,参照第二条),然后设置单元格属性之类的,最后根据玩家数量设置有几行(实际上比玩家数量要多出一行来做菜单栏),然后在菜单栏设置每一列的类型。随后逐行写入玩家的数据。最后在StreamingAssets文件夹创建玩家信息统计的Excle表。
- /// <summary>写入Exicle的方法,如果要重新制定表格的布局,那么就要修改结构体和写入规则 </summary>
- void WriteExicle()
- {
- DirectoryInfo directoryInfo = new DirectoryInfo(Application.dataPath+\\\"Json\\\");//在Json目录下
- FileInfo[] fileInfos = directoryInfo.GetFiles(\\\"*.json\\\"SearchOption.TopDirectoryOnly);//在指向目录的顶层目录下获取所有的json文件
- List<PData> list_pData = new List<PData>(fileInfos.Length);
- for (int i = 0; i < fileInfos.Length; i++)//把每个Json文件读取出来放入数据列表list_pData
- {
- FileStream fileS = fileInfos[i].OpenRead();
- byte[] bytes_read = new byte[fileS.Length];
- fileS.Read(bytes_read0bytes_read.Length);
- fileS.Close();
- fileS.Dispose();
- list_pData.Add(JsonMapper.ToObject<PData>(System.Text.Encoding.UTF8.GetString(bytes_read)));//把json解析成结构体添加进列表中
- }
- HSSFWorkbook hssfw = new HSSFWorkbook();
- ISheet sheet = hssfw.CreateSheet(\\\"Sheet1\\\");
- sheet.SetColumnWidth(0512*10);//设置列宽
- sheet.SetColumnWidth(1 521 * 15);
- sheet.SetColumnWidth(2 512 * 20);
- sheet.SetColumnWidth(3 512 * 15);
- IRow row;//行类
- ICell cell;//单元格类
- for (int i = 0; i <= list_pData.Count; i++)//用第一行来取标题,所以《=最大长度
- {
- row = sheet.CreateRow(i);
- for (int j = 0; j < 4; j++)
- {
- cell = row.CreateCell(j);
- //设置表格的样式
- ICellStyle = hssfw.CreateCellStyle();
- .BorderBottom = BorderStyle.Thin;
- .BorderLeft = BorderStyle.Thin;
- .BorderRight = BorderStyle.Thin;
- .BorderTop = BorderStyle.Thin;
- .Alignment = HorizontalAlignment.Left;
- cell.CellStyle = ;
- if(i == 0)//第一行取标题
- {
- switch (j)
- {
- case 0:
- cell.SetCellValue(\\\"用户名\\\");
- break;
- case 1:
- cell.SetCellValue(\\\"手机号\\\");
- break;
- case 2:
- cell.SetCellValue(\\\"身份证号码\\\");
- break;
- case 3:
- cell.SetCellValue(\\\"用户密码\\\");
- break;
- default:
- break;
- }
- }
- else
- {
- switch (j)
- {
- case 0:
- cell.SetCellValue(list_pData[i-1].name_use);//i需要减1,保证不超出范围
- break;
- case 1:
- cell.SetCellValue(list_pData[i-1].number_phone);
- break;
- case 2:
- cell.SetCellValue(list_pData[i-1].number_IDCard);
- break;
- case 3:
- cell.SetCellValue(list_pData[i-1].password);
- break;
- default:
- break;
- }
- }
- }
- }
- if (Directory.Exists(Application.dataPath + \\\"/StreamingAssets\\\") == false)
- {
- Directory.CreateDirectory(Application.dataPath + \\\"/StreamingAssets\\\");
- print(\\\"streamingAssets创建成功\\\");
- }
- FileStream fs = new FileStream(path_pData FileMode.OpenOrCreate);
- hssfw.Write(fs);
- //byte[] bytes = new byte[fs.Length];
- //fs.Read(bytes0bytes.Length);
- //print(System.Text.Encoding.UTF8.GetString(bytes));
- fs.Close();
- fs.Dispose();
- //ExicleToDataTable(\\\"Sheet1\\\" true);
- }//写入exicle中
4.将Exicle数据转读取存入DataTable中:首先找到表格位置,转换成文件流,然后根据Exicle版本创建workbook,然后获取工作单sheet,然后在工作单中数据返回到DataTable中,根据行列来获取DataTable中的元素。
- /// <summary>
- /// 将Exicle数据转存入DataTable中
- /// </summary>
- /// <param name=\\\"sheelName\\\">工作薄的名字</param>
- /// <param name=\\\"isFirstRowColumn\\\">第一行是否是DataTable的列名</param>
- /// <returns>返回的dataTable</returns>
- DataTable ExicleToDataTable(string sheelName bool isFirstRowColumn)
- {
- dataTable.Clear();
- ISheet sheet = null;
- int startRow = 0;//开始行
- try
- {
- fs = new FileStream(path_pData FileMode.Open FileAccess.Read);
- IWorkbook workbook = null;
- if (path_pData.IndexOf(\\\".xlsx\\\") > 0)//2007
- {
- print(\\\"2007版本的Exicle\\\");
- workbook = new HSSFWorkbook(fs);
- fs.Close();
- fs.Dispose();
- }
- else if (path_pData.IndexOf(\\\".xls\\\") > 0)//2003版本的
- {
- //print(path_pData.IndexOf(\\\".xls\\\"));
- print(\\\"2003版本的Exicle\\\");
- workbook = new HSSFWorkbook(fs);
- fs.Close();
- fs.Dispose();
- }
- if (sheelName != null)
- {
- sheet = workbook.GetSheet(sheelName);//找到对应的工作单赋值
- if (sheet == null)//如果该名称的工作单不存在
- {
- sheet = workbook.GetSheetAt(0);//赋给第一张工作单
- }
- }
- else//如果该名称为空
- {
- sheet = workbook.GetSheetAt(0);//赋给第一张工作单
- }
- if (sheet != null)
- {
- IRow firstRow = sheet.GetRow(0);
- int count_cell = firstRow.LastCellNum;//一行最后一个cell的编号 即总的列数
- if (isFirstRowColumn)
- {
- for (int i = firstRow.RowNum; i < count_cell; i++)//处理第一行的所有单元格
- {
- ICell cell = firstRow.GetCell(i);
- if (cell != null)
- {
- string callValue = cell.StringCellValue;//到这里已经能取到表格的数据了
- print(callValue);//列的名字
- if (callValue != null)//把第一行的所有标题添加进dataTable中
- {
- DataColumn column = new DataColumn(callValue);
- dataTable.Columns.Add(column);
- }
- }
- }
- startRow = sheet.FirstRowNum + 1;//由于第一行是数据类型,所以数据要从第二行开始算
- }
- else//如果不需要第一行菜单栏
- {
- startRow = sheet.FirstRowNum;
- }
- int count_row = sheet.LastRowNum;
- for (int i = startRow; i <= count_row; i++)//添加所有的表格数据
- {
- DataRow dataRow = dataTable.NewRow();//new一个数据行
- IRow row = sheet.GetRow(i);
- if (row == null) continue;
- for (int j = row.FirstCellNum; j < row.LastCellNum; j++)
- {
- if (row.GetCell(j) != null)
- {
- dataRow[j = row.GetCell(j).ToString();
- print(row.GetCell(j).ToString());//获取单元格的文本内容
- }
- }
- dataTable.Rows.Add(dataRow);
- }
- }
- print(dataTable.Rows.Count);
- return dataTable;
- }
- catch (Exception ex)
- {
- print(\\\"捕获异常:\\\" + ex);
- return null;
- }
- }
【最后想说】
写专栏不易,且行且珍惜,附上码云链接:https://gitee.com/likeji/unity-read--write---excel-data.git;这个资源的demo我只展示了Excle数据的读取、查询,用的是ExicleToDataTable()方法,如果要把数据写入Excle表,那么就要在Start调用WriteExicle()方法。
|