最近做了一个读取不规则表格的程序(是从一个表中读出地理信息的经纬高、航向角、增量航向角、车站名称、轨道名称、点类型)
在一个xlsx文件存在5个sheet,因为是固定的格式
| 车站轨道地理信息表 | |||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 数据编号 | 车站名称 | 车站编号 | 所在轨道名称 | 所在轨道编号 | 经度(毫秒) | 纬度(毫秒) | 高程(厘米) | 里程 | 航向角(弧度) | 增量航向角 | |||
| 1 | xx | 1 | 1G | 3 | 400000000 | 130000000 | 100000 | 60.000 | 5.96081359 | -0.02230678 | |||
| 2 | xx | 1 | 1G | 3 | 400000000 | 130000000 | 100000 | 60.015 | 5.93850681 | -0.02990535 | |||
| 编制者:_ 审核者:_, 年 |
月 日 | | | | | | | | | | | | | |
| 制表单位责任人: , 年
月 日 | | | | | | | | | | | | | |
| 建设单位责任人: , 年
月 日 | | | | | | | | | | | | | |
也有空的表格——之后会说明!如果遇到空表格,如果不是关键信息无关紧要,但是其他需要定义的信息会出错
| xx站绝缘节地理信息表 | |||||||||
|---|---|---|---|---|---|---|---|---|---|
| 序号 | 绝缘节名称 | 绝缘节所在区域 | 绝缘节所在轨道名称号 | 经度(毫秒) | 纬度(毫秒) | 高程(厘米) | 航向角(弧度) | 里程 | 备注 |
| 1 | IIIG | 3 | 400000000 | 130000000 | 100000 | 5.566166545 | 92.507 | X信号机 | |
| 2 | IIIG | 3 | 400000000 | 130000000 | 100000 | 5.56617861 | 92.607 | S信号机 |
第三个表原本是这样的—-更不规则了
| xx线下行正向信号数据表 | |||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 序号 | 车站名 | 信号点名称 | 信号点 | 轨道区段 | |||||||||
| 信号点里程 | 经度(毫秒) | 纬度(毫秒) | 高程(厘米) | 航向角(弧度) | 信号点类型 | 绝缘节类型 | 名称 | 载频 | 长度 | 区段属性 | |||
| 1 | 1 | X | 92.507 | 400000000 | 130000000 | 100000 | 5.566166545 | 下行进站信号机 | 绝缘节 |
改成这样了
| xx线下行正向信号数据表 | |||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 序号 | 车站名 | 信号点名称 | 信号点里程 | 经度(毫秒) | 纬度(毫秒) | 高程(厘米) | 航向角(弧度) | 信号点类型 | 绝缘节类型 | 名称 | 载频 | 长度 | 区段属性 |
| 1 | 1 | X | 92.507 | 400000000 | 130000000 | 100000 | 5.566166545 | 下行进站信号机 | 绝缘节 |
上行正向同
第五个表
| 道岔信息表 | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| 序号 | 车站名称 | 道岔编号 | 岔尖里程 | 经度(毫秒) | 纬度(毫秒) | 高程(厘米) | 航向角(弧度) | 正线/侧线 | 定位是否开向侧向 | 备注 |
| 1 | 1 | 1 | 92.61 | 400000000 | 130000000 | 100000 | 5.539135797 | 正线 | 否 |
下面是正文来啦
首先我自己定义了一个保存点的类
才发现C#的一个小招 public int Id { get; set; } = 0;这样相当于设置一个缺省值,不至于为空
public class TxtPoint{public PointType type;public int Id { get; set; } = 0;public string OverlayName { get; set; } = "UnKnown";public string StationName { get; set; } = "UnKnown";public double KiloPos { get; set; } = 0.0;public string TrackName { get; set; } = "UnKnown";public double Latitude { get; set; } = 0.0;public double Longtitude { get; set; } = 0.0;public double Height { get; set; } = 0.0;public double Bear { get; set; } = 0.0;public double DeltaBear { get; set; } = 0.0;public string Tag { get; set; } = "UnKnown";public TxtPoint(){}public TxtPoint(int index, string overlayname, string stationName, string trackname, double lat, double lng, doubleheight, double bear, double deltabear, double KiloPos){this.Id = index;this.OverlayName = overlayname;this.StationName = StationName;this.TrackName = trackname;this.Latitude = lat;this.Longtitude = lng;this.Height = height;this.Bear = bear;this.DeltaBear = deltabear;this.KiloPos = KiloPos;}}public enum PointType{Unknown = 0,Signal = 1,PiecePoint = 2,Switch = 3,Joint = 4}
之后就是打开Excel表操作
NPOI操作分07年前版和07年后版,可以从文件名后缀看出来
XSSFWorkbook—对应xlsx,就是新版,和XSSFRow
HSSFWorkbook-对应xls,旧版—-HSSFRow
这是我的一个Excel提取经纬度的按钮
private void btnImportExcel_ItemClick(object sender, ItemClickEventArgs e){SetOFD(false, "Excel表格文件(*.xlsx,*.xls)|*.xlsx;*.xls");if (oFD.ShowDialog() == DialogResult.OK){string filetype = System.IO.Path.GetExtension(oFD.FileName);if (filetype == ".xlsx"){XSSFWorkbook xSSFSheets = new XSSFWorkbook(oFD.FileName);DataTable dt = ImportToDataTable(oFD.FileName, 0, 1);DataTable dt2 = ImportToDataTable(oFD.FileName, 1, 1);DataTable dt4 = ImportToDataTable(oFD.FileName, 3, 1);DataTable dt3 = ImportToDataTable(oFD.FileName, 2, 1);DataTable dt5 = ImportToDataTable(oFD.FileName, 4, 1);//注意此处一个xlxs文件读取了五个DataTable表还有//因为没有考虑其他不规则表的情况,写的简单了,以后会改AddExcelMap2(dt, oFD.FileName);AddExcelMap2(dt2, oFD.FileName);AddExcelMap2(dt3, oFD.FileName);AddExcelMap2(dt4, oFD.FileName);AddExcelMap2(dt5, oFD.FileName);}else if (filetype == ".xls"){}}}
这部分是我写的导入DataTable的
有几个重点我要写下来怕忘了
NotNullCellCount是自己写的来判断不是合并项,比如表第一行的样式,还有表后也有合并项
还有rows.MoveNext()我试了一下,并不是移动下一行,没有数据就停,他多会儿停我也没搞懂是怎么回事
如果觉得movenext影响速率,可以设置一个计数,记录为这个表整行为空的行数,While(rows.movenext()&&count<N次)的时候可以停
/// <summary>/// 从 Xlxs文件导入数据到 DataTable/// </summary>/// <param name="filePath">文件路径</param>/// <param name="SheetIndex">工作表的索引</param>/// <param name="headerindex">该工作表标题的行数</param>/// <returns></returns>public static DataTable ImportToDataTable(string filePath, int SheetIndex, int headerindex){XSSFWorkbook xssfworkbook;using (FileStream file = new FileStream(filePath, FileMode.Open, FileAccess.Read)){xssfworkbook = new XSSFWorkbook(file);}ISheet sheet = xssfworkbook.GetSheetAt(SheetIndex);String SheetName = xssfworkbook.GetSheetName(SheetIndex);string filename = filePath.Substring(filePath.LastIndexOf("\\") + 1);if (sheet == null){return new DataTable();}System.Collections.IEnumerator rows = sheet.GetRowEnumerator();DataTable dt = new DataTable(filename + SheetName);int columncount = NotNullCellCount((XSSFRow)sheet.GetRow(headerindex));for (int j = 0; j < columncount; j++){ICell cell = sheet.GetRow(headerindex).Cells[j];dt.Columns.Add(cell.ToString());}for (int i = 0; i < headerindex + 1; i++){rows.MoveNext();}int flag = 0;//计数:移动至下一行时不为合并行的个数,避免多次计算while (rows.MoveNext() && flag < 10)//合并行>10停止计算{XSSFRow row = (XSSFRow)rows.Current;int count = NotNullCellCount(row);//返回行的cell个数避免合并情况和无值情况if (count != 0 && count != 1){DataRow Row = dt.NewRow();for (int i = 0; i < columncount; i++){ICell cell = row.GetCell(i);Row[i] = cell == null ? null : cell.ToString();}dt.Rows.Add(Row);}else{flag++;//计算合并行个数}}xssfworkbook = null;return dt;}/// <summary>/// 返回不为空的cell值/// </summary>/// <param name="Row"></param>/// <returns></returns>public static int NotNullCellCount(XSSFRow Row){int j = 0;for (int i = 0; i < Row.Cells.Count; i++){ICell cell = Row.GetCell(i);if (!string.IsNullOrEmpty(GetCellValue(cell).ToString().Trim())){j++;}}return j;}/// <summary>/// 返回不为空的cell值/// </summary>/// <param name="Row"></param>/// <returns></returns>public static int NotNullCellCount(HSSFRow Row){int j = 0;for (int i = 0; i < Row.Cells.Count; i++){ICell cell = Row.GetCell(i);if (!string.IsNullOrEmpty(GetCellValue(cell).ToString().Trim())){j++;}}return j;}
这个是一个很重要的代码,是NPOI操作Excel判断celltype的程序
Excel上的文本、科学计数、日期什么的
/// <summary>/// 获取单元格的值/// </summary>/// <param name="item"></param>/// <returns></returns>public static object GetCellValue(ICell item){if (item == null){return string.Empty;}switch (item.CellType){case CellType.BOOLEAN:return item.BooleanCellValue;case CellType.ERROR:return ErrorEval.GetText(item.ErrorCellValue);case CellType.FORMULA:switch (item.CachedFormulaResultType){case CellType.BOOLEAN:return item.BooleanCellValue;case CellType.ERROR:return ErrorEval.GetText(item.ErrorCellValue);case CellType.NUMERIC:if (DateUtil.IsCellDateFormatted(item)){return item.DateCellValue.ToString("yyyy-MM-dd");}else{return item.NumericCellValue;}case CellType.STRING:string str = item.StringCellValue;if (!string.IsNullOrEmpty(str)){return str.ToString();}else{return string.Empty;}case CellType.Unknown:case CellType.BLANK:default:return string.Empty;}case CellType.NUMERIC:if (DateUtil.IsCellDateFormatted(item)){return item.DateCellValue.ToString("yyyy-MM-dd");}else{return item.NumericCellValue;}case CellType.STRING:string strValue = item.StringCellValue;return strValue.ToString().Trim();case CellType.Unknown:case CellType.BLANK:default:return string.Empty;}}
private void AddExcelMap2(DataTable dt, string filePath){if (!string.IsNullOrEmpty(filePath) && null != dt && dt.Rows.Count > 0){List<TxtPoint> points = DataTableToPoints(dt);Hashtable.Add(dt.TableName, points);TxtPointsToMap(points, dt.TableName);}}private List<TxtPoint> DataTableToPoints(DataTable dt){List<TxtPoint> points = new List<TxtPoint>();string[] strColumns = new string[dt.Columns.Count];for (int i = 0; i < dt.Columns.Count; i++){strColumns[i] = dt.Columns[i].ColumnName.ToString();//DataTable的列名集合}string[] id = new string[] { "数据编号", "编号", "序号" };string[] latname = new string[] { "纬度", "lat", "Lat", "Latitude", "latitude", "纬度(毫秒)" };string[] lngname = new string[] { "经度", "lon", "Lon", "Longtitude", "longtitude", "Lng", "经度(毫秒)" };string[] hgtname = new string[] { "高程", "hgt", "Hgt" };string[] kiloname = new string[] { "公里标", "里程" };string[] stationName = new string[] { "车站名", "车站名称" };string[] trackName = new string[] { "所在轨道名称" };string[] bear = new string[] { "航向角", "航向角(毫秒)" };string[] deltabear = new string[] { "增量航向角" };string[] tag = new string[] { "备注" };//string idc = ReturnColumnName(id, strColumns);string latc = ReturnColumnName(latname, strColumns);string lngc = ReturnColumnName(lngname, strColumns);string hgtc = ReturnColumnName(hgtname, strColumns);string kiloc = ReturnColumnName(kiloname, strColumns);string stac = ReturnColumnName(stationName, strColumns);string tc = ReturnColumnName(trackName, strColumns);string bearc = ReturnColumnName(bear, strColumns);string dbc = ReturnColumnName(deltabear, strColumns);string tagc = ReturnColumnName(tag, strColumns);foreach (DataRow dr in dt.Rows){TxtPoint t = new TxtPoint();t.OverlayName = dt.TableName;if (!string.IsNullOrEmpty(idc) && dr[idc] != DBNull.Value){t.Id = Convert.ToInt32(dr[idc]);}if (!string.IsNullOrEmpty(latc) && dr[latc] != DBNull.Value){t.Latitude = Convert.ToDouble(dr[latc]);}if (!string.IsNullOrEmpty(lngc) && dr[lngc] != DBNull.Value){t.Longtitude = Convert.ToDouble(dr[lngc]);}if (!string.IsNullOrEmpty(hgtc) && dr[hgtc] != DBNull.Value){t.Height = Convert.ToDouble(dr[hgtc]);}if (!string.IsNullOrEmpty(kiloc) && dr[kiloc] != DBNull.Value){t.KiloPos = Convert.ToDouble(dr[kiloc]);}if (!string.IsNullOrEmpty(stac) && dr[stac] != DBNull.Value){t.StationName = dr[stac].ToString();}if (!string.IsNullOrEmpty(tc) && dr[tc] != DBNull.Value){t.TrackName = dr[tc].ToString();}if (!string.IsNullOrEmpty(bearc) && dr[bearc] != DBNull.Value){t.Bear = Convert.ToDouble(dr[bearc]);}if (!string.IsNullOrEmpty(dbc) && dr[dbc] != DBNull.Value){t.DeltaBear = Convert.ToDouble(dr[dbc]);}if (!string.IsNullOrEmpty(tagc) && dr[tagc] != DBNull.Value){t.Tag = dr[tagc].ToString();}points.Add(t);}return points;}public string ReturnColumnName(string[] keyword, string[] columnNames){string temp = "";for (int i = 0; i < columnNames.Length; i++){if (string.IsNullOrEmpty(temp)){for (int j = 0; j < keyword.Length; j++){if (columnNames[i].Contains(keyword[j])){temp = columnNames[i];break;}}}else{break;}}return temp;}//因为GMap里的数据都是纠偏之后的,所以只好保存原始数据的TxtPoint来进行其他操作private void TxtPointsToMap(List<TxtPoint> points, string overlayname){List<string[]> latlngs = new List<string[]>();foreach (TxtPoint p in points){double lat = Math.Round(p.Latitude / 3600000.0, 10);double lng = Math.Round(p.Longtitude / 3600000.0, 10);if (lat != 0 && lng != 0){latlngs.Add(new string[2] { lng.ToString(), lat.ToString() });}}ShowFileLatLng(latlngs, overlayname, true);}
懒了—下次再写———2020.5.20
