[Like] Unity读写Excle表格(使用NPOI.dll)
【前言】
之前接手一个同事的代码时,发现其中有个项目用到了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()方法。




某些代码由于粘贴过来时格式出现问题,老是修改不了,建议下载案例对比调试
  • 板凳 u3d_xu
  • 2020-11-11 10:14:18
牛逼 收藏下
楼主666666666666666666666666
666666666666666666666666
Plugin中dll缺失啦,只有文件了
引用: q873438526 发表于 2020-11-12 10:49
Plugin中dll缺失啦,只有文件了

sourcetree好像上传不了dll文件,我直接从码云上传了,下载康康吧
12-7日修改帖子格式,已经尽量减少发布帖子造成的字符串格式错误,对比源码时尽量忽略“\\”样式的错误
mark一下
6666666666666
楼主好人呐,期待更新word 读写
6666666666666666666666
  • 13# 光亮
  • 2021-1-21 10:28:01
秀啊 钩子
可以的   
楼主,好东西啊,牛逼666,
12下一页