最近做了一个读取不规则表格的程序(是从一个表中读出地理信息的经纬高、航向角、增量航向角、车站名称、轨道名称、点类型)
    在一个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;这样相当于设置一个缺省值,不至于为空

    1. public class TxtPoint
    2. {
    3. public PointType type;
    4. public int Id { get; set; } = 0;
    5. public string OverlayName { get; set; } = "UnKnown";
    6. public string StationName { get; set; } = "UnKnown";
    7. public double KiloPos { get; set; } = 0.0;
    8. public string TrackName { get; set; } = "UnKnown";
    9. public double Latitude { get; set; } = 0.0;
    10. public double Longtitude { get; set; } = 0.0;
    11. public double Height { get; set; } = 0.0;
    12. public double Bear { get; set; } = 0.0;
    13. public double DeltaBear { get; set; } = 0.0;
    14. public string Tag { get; set; } = "UnKnown";
    15. public TxtPoint()
    16. {
    17. }
    18. public TxtPoint(int index, string overlayname, string stationName, string trackname, double lat, double lng, double
    19. height, double bear, double deltabear, double KiloPos)
    20. {
    21. this.Id = index;
    22. this.OverlayName = overlayname;
    23. this.StationName = StationName;
    24. this.TrackName = trackname;
    25. this.Latitude = lat;
    26. this.Longtitude = lng;
    27. this.Height = height;
    28. this.Bear = bear;
    29. this.DeltaBear = deltabear;
    30. this.KiloPos = KiloPos;
    31. }
    32. }
    33. public enum PointType
    34. {
    35. Unknown = 0,
    36. Signal = 1,
    37. PiecePoint = 2,
    38. Switch = 3,
    39. Joint = 4
    40. }

    之后就是打开Excel表操作
    NPOI操作分07年前版和07年后版,可以从文件名后缀看出来
    XSSFWorkbook—对应xlsx,就是新版,和XSSFRow
    HSSFWorkbook-对应xls,旧版—-HSSFRow
    这是我的一个Excel提取经纬度的按钮

    1. private void btnImportExcel_ItemClick(object sender, ItemClickEventArgs e)
    2. {
    3. SetOFD(false, "Excel表格文件(*.xlsx,*.xls)|*.xlsx;*.xls");
    4. if (oFD.ShowDialog() == DialogResult.OK)
    5. {
    6. string filetype = System.IO.Path.GetExtension(oFD.FileName);
    7. if (filetype == ".xlsx")
    8. {
    9. XSSFWorkbook xSSFSheets = new XSSFWorkbook(oFD.FileName);
    10. DataTable dt = ImportToDataTable(oFD.FileName, 0, 1);
    11. DataTable dt2 = ImportToDataTable(oFD.FileName, 1, 1);
    12. DataTable dt4 = ImportToDataTable(oFD.FileName, 3, 1);
    13. DataTable dt3 = ImportToDataTable(oFD.FileName, 2, 1);
    14. DataTable dt5 = ImportToDataTable(oFD.FileName, 4, 1);
    15. //注意此处一个xlxs文件读取了五个DataTable表还有
    16. //因为没有考虑其他不规则表的情况,写的简单了,以后会改
    17. AddExcelMap2(dt, oFD.FileName);
    18. AddExcelMap2(dt2, oFD.FileName);
    19. AddExcelMap2(dt3, oFD.FileName);
    20. AddExcelMap2(dt4, oFD.FileName);
    21. AddExcelMap2(dt5, oFD.FileName);
    22. }
    23. else if (filetype == ".xls")
    24. {
    25. }
    26. }
    27. }

    这部分是我写的导入DataTable的
    有几个重点我要写下来怕忘了
    NotNullCellCount是自己写的来判断不是合并项,比如表第一行的样式,还有表后也有合并项
    还有rows.MoveNext()我试了一下,并不是移动下一行,没有数据就停,他多会儿停我也没搞懂是怎么回事
    如果觉得movenext影响速率,可以设置一个计数,记录为这个表整行为空的行数,While(rows.movenext()&&count<N次)的时候可以停

    1. /// <summary>
    2. /// 从 Xlxs文件导入数据到 DataTable
    3. /// </summary>
    4. /// <param name="filePath">文件路径</param>
    5. /// <param name="SheetIndex">工作表的索引</param>
    6. /// <param name="headerindex">该工作表标题的行数</param>
    7. /// <returns></returns>
    8. public static DataTable ImportToDataTable(string filePath, int SheetIndex, int headerindex)
    9. {
    10. XSSFWorkbook xssfworkbook;
    11. using (FileStream file = new FileStream(filePath, FileMode.Open, FileAccess.Read))
    12. {
    13. xssfworkbook = new XSSFWorkbook(file);
    14. }
    15. ISheet sheet = xssfworkbook.GetSheetAt(SheetIndex);
    16. String SheetName = xssfworkbook.GetSheetName(SheetIndex);
    17. string filename = filePath.Substring(filePath.LastIndexOf("\\") + 1);
    18. if (sheet == null)
    19. {
    20. return new DataTable();
    21. }
    22. System.Collections.IEnumerator rows = sheet.GetRowEnumerator();
    23. DataTable dt = new DataTable(filename + SheetName);
    24. int columncount = NotNullCellCount((XSSFRow)sheet.GetRow(headerindex));
    25. for (int j = 0; j < columncount; j++)
    26. {
    27. ICell cell = sheet.GetRow(headerindex).Cells[j];
    28. dt.Columns.Add(cell.ToString());
    29. }
    30. for (int i = 0; i < headerindex + 1; i++)
    31. {
    32. rows.MoveNext();
    33. }
    34. int flag = 0;//计数:移动至下一行时不为合并行的个数,避免多次计算
    35. while (rows.MoveNext() && flag < 10)//合并行>10停止计算
    36. {
    37. XSSFRow row = (XSSFRow)rows.Current;
    38. int count = NotNullCellCount(row);//返回行的cell个数避免合并情况和无值情况
    39. if (count != 0 && count != 1)
    40. {
    41. DataRow Row = dt.NewRow();
    42. for (int i = 0; i < columncount; i++)
    43. {
    44. ICell cell = row.GetCell(i);
    45. Row[i] = cell == null ? null : cell.ToString();
    46. }
    47. dt.Rows.Add(Row);
    48. }
    49. else
    50. {
    51. flag++;//计算合并行个数
    52. }
    53. }
    54. xssfworkbook = null;
    55. return dt;
    56. }
    57. /// <summary>
    58. /// 返回不为空的cell值
    59. /// </summary>
    60. /// <param name="Row"></param>
    61. /// <returns></returns>
    62. public static int NotNullCellCount(XSSFRow Row)
    63. {
    64. int j = 0;
    65. for (int i = 0; i < Row.Cells.Count; i++)
    66. {
    67. ICell cell = Row.GetCell(i);
    68. if (!string.IsNullOrEmpty(GetCellValue(cell).ToString().Trim()))
    69. {
    70. j++;
    71. }
    72. }
    73. return j;
    74. }
    75. /// <summary>
    76. /// 返回不为空的cell值
    77. /// </summary>
    78. /// <param name="Row"></param>
    79. /// <returns></returns>
    80. public static int NotNullCellCount(HSSFRow Row)
    81. {
    82. int j = 0;
    83. for (int i = 0; i < Row.Cells.Count; i++)
    84. {
    85. ICell cell = Row.GetCell(i);
    86. if (!string.IsNullOrEmpty(GetCellValue(cell).ToString().Trim()))
    87. {
    88. j++;
    89. }
    90. }
    91. return j;
    92. }

    这个是一个很重要的代码,是NPOI操作Excel判断celltype的程序
    Excel上的文本、科学计数、日期什么的

    1. /// <summary>
    2. /// 获取单元格的值
    3. /// </summary>
    4. /// <param name="item"></param>
    5. /// <returns></returns>
    6. public static object GetCellValue(ICell item)
    7. {
    8. if (item == null)
    9. {
    10. return string.Empty;
    11. }
    12. switch (item.CellType)
    13. {
    14. case CellType.BOOLEAN:
    15. return item.BooleanCellValue;
    16. case CellType.ERROR:
    17. return ErrorEval.GetText(item.ErrorCellValue);
    18. case CellType.FORMULA:
    19. switch (item.CachedFormulaResultType)
    20. {
    21. case CellType.BOOLEAN:
    22. return item.BooleanCellValue;
    23. case CellType.ERROR:
    24. return ErrorEval.GetText(item.ErrorCellValue);
    25. case CellType.NUMERIC:
    26. if (DateUtil.IsCellDateFormatted(item))
    27. {
    28. return item.DateCellValue.ToString("yyyy-MM-dd");
    29. }
    30. else
    31. {
    32. return item.NumericCellValue;
    33. }
    34. case CellType.STRING:
    35. string str = item.StringCellValue;
    36. if (!string.IsNullOrEmpty(str))
    37. {
    38. return str.ToString();
    39. }
    40. else
    41. {
    42. return string.Empty;
    43. }
    44. case CellType.Unknown:
    45. case CellType.BLANK:
    46. default:
    47. return string.Empty;
    48. }
    49. case CellType.NUMERIC:
    50. if (DateUtil.IsCellDateFormatted(item))
    51. {
    52. return item.DateCellValue.ToString("yyyy-MM-dd");
    53. }
    54. else
    55. {
    56. return item.NumericCellValue;
    57. }
    58. case CellType.STRING:
    59. string strValue = item.StringCellValue;
    60. return strValue.ToString().Trim();
    61. case CellType.Unknown:
    62. case CellType.BLANK:
    63. default:
    64. return string.Empty;
    65. }
    66. }
    1. private void AddExcelMap2(DataTable dt, string filePath)
    2. {
    3. if (!string.IsNullOrEmpty(filePath) && null != dt && dt.Rows.Count > 0)
    4. {
    5. List<TxtPoint> points = DataTableToPoints(dt);
    6. Hashtable.Add(dt.TableName, points);
    7. TxtPointsToMap(points, dt.TableName);
    8. }
    9. }
    10. private List<TxtPoint> DataTableToPoints(DataTable dt)
    11. {
    12. List<TxtPoint> points = new List<TxtPoint>();
    13. string[] strColumns = new string[dt.Columns.Count];
    14. for (int i = 0; i < dt.Columns.Count; i++)
    15. {
    16. strColumns[i] = dt.Columns[i].ColumnName.ToString();//DataTable的列名集合
    17. }
    18. string[] id = new string[] { "数据编号", "编号", "序号" };
    19. string[] latname = new string[] { "纬度", "lat", "Lat", "Latitude", "latitude", "纬度(毫秒)" };
    20. string[] lngname = new string[] { "经度", "lon", "Lon", "Longtitude", "longtitude", "Lng", "经度(毫秒)" };
    21. string[] hgtname = new string[] { "高程", "hgt", "Hgt" };
    22. string[] kiloname = new string[] { "公里标", "里程" };
    23. string[] stationName = new string[] { "车站名", "车站名称" };
    24. string[] trackName = new string[] { "所在轨道名称" };
    25. string[] bear = new string[] { "航向角", "航向角(毫秒)" };
    26. string[] deltabear = new string[] { "增量航向角" };
    27. string[] tag = new string[] { "备注" };
    28. //
    29. string idc = ReturnColumnName(id, strColumns);
    30. string latc = ReturnColumnName(latname, strColumns);
    31. string lngc = ReturnColumnName(lngname, strColumns);
    32. string hgtc = ReturnColumnName(hgtname, strColumns);
    33. string kiloc = ReturnColumnName(kiloname, strColumns);
    34. string stac = ReturnColumnName(stationName, strColumns);
    35. string tc = ReturnColumnName(trackName, strColumns);
    36. string bearc = ReturnColumnName(bear, strColumns);
    37. string dbc = ReturnColumnName(deltabear, strColumns);
    38. string tagc = ReturnColumnName(tag, strColumns);
    39. foreach (DataRow dr in dt.Rows)
    40. {
    41. TxtPoint t = new TxtPoint();
    42. t.OverlayName = dt.TableName;
    43. if (!string.IsNullOrEmpty(idc) && dr[idc] != DBNull.Value)
    44. {
    45. t.Id = Convert.ToInt32(dr[idc]);
    46. }
    47. if (!string.IsNullOrEmpty(latc) && dr[latc] != DBNull.Value)
    48. {
    49. t.Latitude = Convert.ToDouble(dr[latc]);
    50. }
    51. if (!string.IsNullOrEmpty(lngc) && dr[lngc] != DBNull.Value)
    52. {
    53. t.Longtitude = Convert.ToDouble(dr[lngc]);
    54. }
    55. if (!string.IsNullOrEmpty(hgtc) && dr[hgtc] != DBNull.Value)
    56. {
    57. t.Height = Convert.ToDouble(dr[hgtc]);
    58. }
    59. if (!string.IsNullOrEmpty(kiloc) && dr[kiloc] != DBNull.Value)
    60. {
    61. t.KiloPos = Convert.ToDouble(dr[kiloc]);
    62. }
    63. if (!string.IsNullOrEmpty(stac) && dr[stac] != DBNull.Value)
    64. {
    65. t.StationName = dr[stac].ToString();
    66. }
    67. if (!string.IsNullOrEmpty(tc) && dr[tc] != DBNull.Value)
    68. {
    69. t.TrackName = dr[tc].ToString();
    70. }
    71. if (!string.IsNullOrEmpty(bearc) && dr[bearc] != DBNull.Value)
    72. {
    73. t.Bear = Convert.ToDouble(dr[bearc]);
    74. }
    75. if (!string.IsNullOrEmpty(dbc) && dr[dbc] != DBNull.Value)
    76. {
    77. t.DeltaBear = Convert.ToDouble(dr[dbc]);
    78. }
    79. if (!string.IsNullOrEmpty(tagc) && dr[tagc] != DBNull.Value)
    80. {
    81. t.Tag = dr[tagc].ToString();
    82. }
    83. points.Add(t);
    84. }
    85. return points;
    86. }
    87. public string ReturnColumnName(string[] keyword, string[] columnNames)
    88. {
    89. string temp = "";
    90. for (int i = 0; i < columnNames.Length; i++)
    91. {
    92. if (string.IsNullOrEmpty(temp))
    93. {
    94. for (int j = 0; j < keyword.Length; j++)
    95. {
    96. if (columnNames[i].Contains(keyword[j]))
    97. {
    98. temp = columnNames[i];
    99. break;
    100. }
    101. }
    102. }
    103. else
    104. {
    105. break;
    106. }
    107. }
    108. return temp;
    109. }
    110. //因为GMap里的数据都是纠偏之后的,所以只好保存原始数据的TxtPoint来进行其他操作
    111. private void TxtPointsToMap(List<TxtPoint> points, string overlayname)
    112. {
    113. List<string[]> latlngs = new List<string[]>();
    114. foreach (TxtPoint p in points)
    115. {
    116. double lat = Math.Round(p.Latitude / 3600000.0, 10);
    117. double lng = Math.Round(p.Longtitude / 3600000.0, 10);
    118. if (lat != 0 && lng != 0)
    119. {
    120. latlngs.Add(new string[2] { lng.ToString(), lat.ToString() });
    121. }
    122. }
    123. ShowFileLatLng(latlngs, overlayname, true);
    124. }

    懒了—下次再写———2020.5.20