最近在做Excel模板数据导出,要求在Excel展示数据分页结果,做分页时发现npoi复制行有个bug【这种情况并不会百分百复现,sheet.CopyRow,备注下面的那一列还是会正常被复制显示完整的】,
本来第一行的文字在A1下是可以完全显示的,但是复制的第二页之后,就不会完整显示了,如下
经过调查,原因是复制后的单元格被改成了stirng类型,默认应该是blank
为了避免这种随机情况,只能自己重写一下CopyRow方法了
public static class NpoiExpand { /// <summary> /// sheet 页自动分页 /// </summary> /// <param name="sheet">工作表</param> /// <param name="pageSize">每页占多少行</param> /// <param name="pageCount">总页数</param> /// <param name="workbook">工作簿</param> public static void AutoPage(this ISheet sheet, int pageSize, int pageCount, IWorkbook workbook) { for (int p = 1; p < pageCount; p++) { for (int i = 0; i < pageSize; i++) { sheet.CopyRow(i, p * pageSize + i, workbook, false); } sheet.SetRowBreak(p * pageSize - 1); } } /// <summary> /// 将源单元格的值复制到目标单元格。 /// </summary> /// <param name="sourceCell">要从中复制值的源单元格。</param> /// <param name="targetCell">要将值复制到的目标单元格。</param> public static void SetCellValue(this ICell sourceCell, ICell targetCell) { switch (sourceCell.CellType) { case CellType.Blank: targetCell.SetBlank(); break; case CellType.Boolean: targetCell.SetCellValue(sourceCell.BooleanCellValue); break; case CellType.Error: targetCell.SetCellErrorValue(sourceCell.ErrorCellValue); break; case CellType.Formula: targetCell.SetCellFormula(sourceCell.CellFormula); break; case CellType.Numeric: if (DateUtil.IsCellDateFormatted(sourceCell)) { if (sourceCell.DateCellValue.HasValue) { targetCell.SetCellValue(sourceCell.DateCellValue.Value); } else { // 处理空日期值的情况,这里可以根据需要进行操作 // 例如:设置一个默认日期值或者其他处理方式 } } else { targetCell.SetCellValue(sourceCell.NumericCellValue); } break; case CellType.String: targetCell.SetCellValue(sourceCell.RichStringCellValue); break; } } /// <summary> /// 将源行的内容复制到目标工作表的目标行中。 /// </summary> /// <param name="targetSheet">目标工作表</param> /// <param name="sourceRowNum">源行号</param> /// <param name="targetRowNum">目标行号</param> /// <param name="targetWorkbook">目标工作簿</param> /// <param name="isCopyCellValue">是否复制单元格的值</param> public static void CopyRow(this ISheet targetSheet, int sourceRowNum, int targetRowNum, IWorkbook targetWorkbook, bool isCopyCellValue = false) { IRow sourceRow = targetSheet.GetRow(sourceRowNum); IRow targetRow = targetSheet.GetRow(targetRowNum); if (targetRow == null) { targetRow = targetSheet.CreateRow(targetRowNum); } // 设置目标行的高度与源行相同 targetRow.Height = sourceRow.Height; // 创建一个样式缓存,用于重用单元格样式 Dictionary<ICellStyle, ICellStyle> styleCache = new Dictionary<ICellStyle, ICellStyle>(); // 如果源行具有自定义样式,将此样式复制到目标行 if (sourceRow.RowStyle != null) { ICellStyle newRowStyle; if (!styleCache.TryGetValue(sourceRow.RowStyle, out newRowStyle)) { // 如果样式尚未缓存,创建新样式并将其添加到缓存中 newRowStyle = targetWorkbook.CreateCellStyle(); newRowStyle.CloneStyleFrom(sourceRow.RowStyle); styleCache[sourceRow.RowStyle] = newRowStyle; } targetRow.RowStyle = newRowStyle; } // 遍历源行的所有单元格进行复制 for (int i = 0; i < sourceRow.LastCellNum; i++) { ICell sourceCell = sourceRow.GetCell(i); if (sourceCell != null) { // 在目标行创建新的单元格,并设置相同的单元格类型 ICell targetCell = targetRow.CreateCell(i, sourceCell.CellType); targetCell.SetCellType(sourceCell.CellType); // 如果源单元格具有样式,将此样式复制到目标单元格 if (sourceCell.CellStyle != null) { ICellStyle newCellStyle; if (!styleCache.TryGetValue(sourceCell.CellStyle, out newCellStyle)) { // 如果样式尚未缓存,创建新样式并将其添加到缓存中 newCellStyle = targetWorkbook.CreateCellStyle(); newCellStyle.CloneStyleFrom(sourceCell.CellStyle); styleCache[sourceCell.CellStyle] = newCellStyle; } targetCell.CellStyle = newCellStyle; } // 复制单元格的注释 if (sourceCell.CellComment != null) { targetCell.CellComment = sourceCell.CellComment; } // 复制单元格的超链接 if (sourceCell.Hyperlink != null) { targetCell.Hyperlink = sourceCell.Hyperlink; } if (isCopyCellValue) sourceCell.SetCellValue(targetCell); } } for (int i = 0; i < targetSheet.NumMergedRegions; i++) { CellRangeAddress mergedRegion = targetSheet.GetMergedRegion(i); if (mergedRegion.FirstRow >= targetRowNum && mergedRegion.LastRow <= targetRowNum) { // 如果合并区域与目标行重叠,将其拆分 targetSheet.RemoveMergedRegion(i); i--; } } // 复制合并的单元格区域 for (int i = 0; i < sourceRow.Sheet.NumMergedRegions; i++) { CellRangeAddress mergedRegion = sourceRow.Sheet.GetMergedRegion(i); if (mergedRegion.FirstRow == sourceRow.RowNum) { // 如果源合并区域的首行是当前源行,将此合并区域复制到目标行 CellRangeAddress newMergedRegion = new CellRangeAddress( targetRow.RowNum, targetRow.RowNum + mergedRegion.LastRow - mergedRegion.FirstRow, mergedRegion.FirstColumn, mergedRegion.LastColumn ); targetSheet.AddMergedRegion(newMergedRegion); } } } /// <summary> /// 仅复制源行的样式到目标工作表的目标行。 /// </summary> /// <param name="targetSheet">目标工作表</param> /// <param name="sourceRowNum">源行号</param> /// <param name="targetRowNum">目标行号</param> /// <param name="targetWorkbook">目标工作簿</param> public static void CopyRowCellStyle(this ISheet targetSheet, int sourceRowNum, int targetRowNum, IWorkbook targetWorkbook) { IRow sourceRow = targetSheet.GetRow(sourceRowNum); IRow targetRow = targetSheet.GetRow(targetRowNum); if (targetRow == null) { targetRow = targetSheet.CreateRow(targetRowNum); } // 设置目标行的高度与源行相同 targetRow.Height = sourceRow.Height; // 创建一个样式缓存,用于重用单元格样式 Dictionary<ICellStyle, ICellStyle> styleCache = new Dictionary<ICellStyle, ICellStyle>(); // 如果源行具有自定义样式,将此样式复制到目标行 if (sourceRow.RowStyle != null) { ICellStyle newRowStyle; if (!styleCache.TryGetValue(sourceRow.RowStyle, out newRowStyle)) { // 如果样式尚未缓存,创建新样式并将其添加到缓存中 newRowStyle = targetWorkbook.CreateCellStyle(); newRowStyle.CloneStyleFrom(sourceRow.RowStyle); styleCache[sourceRow.RowStyle] = newRowStyle; } targetRow.RowStyle = newRowStyle; } // 遍历源行的所有单元格进行样式复制 for (int i = 0; i < sourceRow.LastCellNum; i++) { ICell sourceCell = sourceRow.GetCell(i); if (sourceCell != null) { // 在目标行创建新的单元格,并设置相同的单元格类型 ICell targetCell = targetRow.CreateCell(i, sourceCell.CellType); targetCell.SetCellType(sourceCell.CellType); // 如果源单元格具有样式,将此样式复制到目标单元格 if (sourceCell.CellStyle != null) { ICellStyle newCellStyle; if (!styleCache.TryGetValue(sourceCell.CellStyle, out newCellStyle)) { // 如果样式尚未缓存,创建新样式并将其添加到缓存中 newCellStyle = targetWorkbook.CreateCellStyle(); newCellStyle.CloneStyleFrom(sourceCell.CellStyle); styleCache[sourceCell.CellStyle] = newCellStyle; } targetCell.CellStyle = newCellStyle; } } } } /// <summary> /// 将 .xls 文件转换为 .xlsx 文件 /// </summary> /// <param name="filePath">要转换的文件路径</param> /// <returns>转换后的 .xlsx 文件路径</returns> public static string ConvertXlsToXlsx(this string filePath) { if (!File.Exists(filePath)) throw new FileNotFoundException("文件不存在!", filePath); if (Path.GetExtension(filePath).ToLower() == ".xls") { var xlsxFilePath = filePath.Replace("xls", "xlsx"); Application excelApp = new Application(); Workbook workbook = excelApp.Workbooks.Open(filePath); workbook.Saved = true; workbook.SaveAs(xlsxFilePath, XlFileFormat.xlOpenXMLWorkbook); workbook.Close(true); excelApp.Quit(); System.Runtime.InteropServices.Marshal.ReleaseComObject(workbook); workbook = null; System.Runtime.InteropServices.Marshal.ReleaseComObject(excelApp); excelApp = null; GC.Collect(); return xlsxFilePath; } return filePath; } /// <summary> /// 打开一个 Excel 文件并返回工作簿对象。 /// </summary> /// <param name="filePath">Excel 文件的路径。</param> /// <returns>已打开的 Excel 工作簿对象。</returns> public static IWorkbook OpenExcel(this string filePath) { if (!File.Exists(filePath)) throw new FileNotFoundException("文件不存在!", filePath); IWorkbook workbook = WorkbookFactory.Create(filePath); return workbook; } /// <summary> /// 将工作簿保存为文件。 /// </summary> /// <param name="workBook">要保存的工作簿对象。</param> /// <param name="saveFileFullPath">要保存的文件的完整路径。</param> /// <returns>保存的文件的完整路径。</returns> public static string SaveExcelToFile(this IWorkbook workBook, string saveFileFullPath) { using (MemoryStream memoryStream = new MemoryStream()) { workBook.Write(memoryStream); // 将工作簿写入内存流 var fileBytes = memoryStream.ToArray(); // 将内存流转换为字节数组 File.WriteAllBytes(saveFileFullPath, fileBytes); return saveFileFullPath; } } /// <summary> /// 获取单元格的值。 /// </summary> /// <param name="cell">要获取值的单元格</param> /// <returns>单元格的值,如果单元格为空则返回 DBNull.Value</returns> public static object GetCellValue(this ICell cell) { if (cell == null) return DBNull.Value; switch (cell.CellType) { case CellType.Numeric: if (DateUtil.IsCellDateFormatted(cell)) return cell.DateCellValue; else return cell.NumericCellValue; case CellType.String: return cell.StringCellValue; case CellType.Boolean: return cell.BooleanCellValue; case CellType.Formula: return cell.CellFormula; default: return DBNull.Value; } } }
var newFileSavePath = Path.Combine(Directory.GetCurrentDirectory(), "Source.output.xlsx");//保存生成的文件 var path = Path.Combine(Directory.GetCurrentDirectory(), "source.xlsx"); var workbook = path.OpenExcel(); var sheet = workbook.GetSheetAt(0); sheet.AutoPage(14, 3, workbook);Main方法
最终结果
标签:sourceRow,记录,样式,单元格,Npoi,targetCell,复制,CellType,sourceCell From: https://www.cnblogs.com/INetIMVC/p/18303121