馬上注冊,結交更多好友,享用更多功能,讓你輕松玩轉社區。
您需要 登錄 才可以下載或查看,沒有帳號?注冊帳號
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()方法。
|