老师布置了一个任务,就是从txt文件中提取到一些信息
然后有一个Excel的模板
需要把数据导入进去,并且完成校验,最后保存Excel文件等一系列事件
我首先想到了国人开发的NPOI—因为它可以处理Excel和Word文件等等
在我处理的过程中,出现了一个问题,可能因为自己学艺不精,所以在此贴出自己写的代码为以后学会了纠错
方法一:NPOI——现在没有找到为什么ShiftRow会删除下两行的内容的问题
这些代码分别是打开workbook、插入N行数据
public HSSFWorkbook NPOIOpenExcel(string FileName)
{
HSSFWorkbook MyHSSFWorkBook;
FileStream fs = new FileStream(FileName, FileMode.Open);
MyHSSFWorkBook = new HSSFWorkbook(fs);
return MyHSSFWorkBook;
}
public XSSFWorkbook NPOIOpenExcel2(string FileName)
{
XSSFWorkbook MyXSSFWorkBook;
FileStream fs = new FileStream(FileName, FileMode.Open);
MyXSSFWorkBook = new XSSFWorkbook(fs);
return MyXSSFWorkBook;
}
//参数说明
//第一个:指定操作的Sheet。
//第二个:指定在第几行指入(插入行的位置)
//第三个:指定要插入多少行
//第四个:源单元格格式的行,
private void MyInsertRow(ref HSSFSheet sheet, int startrow, int rowcount, HSSFRow FormatRow)
{
//批量移动行
sheet.ShiftRows(startrow,sheet.LastRowNum,rowcount,true,false,true);
//对批量移动后空出的空行插,创建相应的行,并以插入行的上一行为格式源(即:插入行-1的那一行)
for (int i = startrow; i < startrow + rowcount - 1; i++)
{
HSSFRow targetRow = null;
HSSFCell sourceCell = null;
HSSFCell targetCell = null;
targetRow = (HSSFRow)sheet.CreateRow(i + 1);
for (int m = FormatRow.FirstCellNum; m < FormatRow.LastCellNum; m++)
{
sourceCell = (HSSFCell)FormatRow.GetCell(m);
if (sourceCell == null)
continue;
targetCell = (HSSFCell)targetRow.CreateCell(m);
//targetCell.Encoding = sourceCell.Encoding;
targetCell.CellStyle = sourceCell.CellStyle;
targetCell.SetCellType(sourceCell.CellType);
}
//CopyRow(sourceRow, targetRow);
//Util.CopyRow(sheet, sourceRow, targetRow);
}
HSSFRow firstTargetRow = (HSSFRow)sheet.GetRow(startrow);
HSSFCell firstSourceCell = null;
HSSFCell firstTargetCell = null;
for (int m = FormatRow.FirstCellNum; m < FormatRow.LastCellNum; m++)
{
firstSourceCell = (HSSFCell)FormatRow.GetCell(m);
if (firstSourceCell == null)
continue;
firstTargetCell = (HSSFCell)firstTargetRow.CreateCell(m);
//firstTargetCell.Encoding = firstSourceCell.Encoding;
firstTargetCell.CellStyle = firstSourceCell.CellStyle;
firstTargetCell.SetCellType(firstSourceCell.CellType);
}
}
private void MyInsertRow(ref XSSFSheet sheet, int startrow, int rowcount, XSSFRow FormatRow)
{
//批量移动行
sheet.ShiftRows(startrow, sheet.LastRowNum, rowcount, true, false);
//对批量移动后空出的空行插,创建相应的行,并以插入行的上一行为格式源(即:插入行-1的那一行)
for (int i = startrow; i < startrow + rowcount - 1; i++)
{
XSSFRow targetRow = null;
XSSFCell sourceCell = null;
XSSFCell targetCell = null;
targetRow = (XSSFRow)sheet.CreateRow(i + 1);
for (int m = FormatRow.FirstCellNum; m < FormatRow.LastCellNum; m++)
{
sourceCell = (XSSFCell)FormatRow.GetCell(m);
if (sourceCell == null)
continue;
targetCell = (XSSFCell)targetRow.CreateCell(m);
//targetCell.Encoding = sourceCell.Encoding;
targetCell.CellStyle = sourceCell.CellStyle;
targetCell.SetCellType(sourceCell.CellType);
}
//CopyRow(sourceRow, targetRow);
//Util.CopyRow(sheet, sourceRow, targetRow);
}
XSSFRow firstTargetRow = (XSSFRow)sheet.GetRow(startrow);
XSSFCell firstSourceCell = null;
XSSFCell firstTargetCell = null;
for (int m = FormatRow.FirstCellNum; m < FormatRow.LastCellNum; m++)
{
firstSourceCell = (XSSFCell)FormatRow.GetCell(m);
if (firstSourceCell == null)
continue;
firstTargetCell = (XSSFCell)firstTargetRow.CreateCell(m);
//firstTargetCell.Encoding = firstSourceCell.Encoding;
firstTargetCell.CellStyle = firstSourceCell.CellStyle;
firstTargetCell.SetCellType(firstSourceCell.CellType);
}
}
private void SaveExcel(string dir,XSSFWorkbook workbook)
{
using (FileStream files = new FileStream(dir, FileMode.Create))
{
workbook.Write(files);
}
}
但是插入N行之后,最后三行footer内容消失了
用的是这个方法
private void ButtonClick(object sender,ItemClickEventArgs e)
{
DirectoryInfo d = GetDirectoryInfo(3);
string modelPath = d.FullName + "CTCS_ExcelModel.xlsx";
List<TxtPoint> points = new List<TxtPoint>();
points.Add(new TxtPoint { Bear = 0.29038476533, DeltaBear = 0.089987576 });
points.Add(new TxtPoint { Bear = 0.23984676, DeltaBear = 0.1231243566 });
points.Add(new TxtPoint { Bear = 0.012398675, DeltaBear = 11.2345645756 });
points.Add(new TxtPoint { Bear = 0.29038476533, DeltaBear = 0.089987576 });
points.Add(new TxtPoint { Bear = 0.23984676, DeltaBear = 0.1231243566 });
points.Add(new TxtPoint { Bear = 0.012398675, DeltaBear = 11.2345645756 });
points.Add(new TxtPoint { Bear = 0.012398675, DeltaBear = 11.2345645756 });
points.Add(new TxtPoint { Bear = 0.29038476533, DeltaBear = 0.089987576 });
points.Add(new TxtPoint { Bear = 0.23984676, DeltaBear = 0.1231243566 });
points.Add(new TxtPoint { Bear = 0.012398675, DeltaBear = 11.2345645756 });
XSSFWorkbook workbook = NPOIOpenExcel2(modelPath);
XSSFSheet sheet = (XSSFSheet)workbook.GetSheetAt(0);
XSSFRow formatRow = (XSSFRow)sheet.GetRow(3);
MyInsertRow(ref sheet, 6, points.Count - 4, formatRow);
////ImportData(ref sheet, 2, points);//导入数据
SaveExcel(d.FullName + "副本CTCS_ExcelModel.xlsx", workbook);
}
否则用这个方法,则会出现这个问题
/// <summary>
/// NPOI使用ShiftRows向Excel插入行,并复制原有样式
/// </summary>
/// <param name="file"></param>模板文件
/// <param name="dir">导出路径</param>
public void ShiftRows(string file,string dir,List<TxtPoint> txtPoints)
{
try
{
FileStream fs = new FileStream(file, FileMode.Open);
XSSFWorkbook workbook = new XSSFWorkbook(fs);
ISheet sheet = (XSSFSheet)workbook.GetSheetAt(0);
int startRow = 3;// 6;//开始插入行索引
//列控数据表0-地理信息表默认可填充四行数据
//当导入的DataTable超出4行时,使用ShiftRows插入行
if (txtPoints.Count > 4)
{
//插入行
Console.WriteLine(sheet.LastRowNum.ToString());
sheet.ShiftRows(startRow, sheet.LastRowNum, txtPoints.Count - 4, false, false);// txtPoints.Count - 4, true, false);
//sheet.ShiftRows(startRow, sheet.LastRowNum, txtPoints.Count - 4, true, false);
var rowSource = sheet.GetRow(2);
var rowStyle = rowSource.RowStyle;//获取当前行样式
for (int i = startRow; i < startRow + txtPoints.Count-1; i++)
{
var rowInsert = sheet.CreateRow(i);
if (rowStyle != null)
{
rowInsert.RowStyle = rowStyle;
rowInsert.Height = rowSource.Height;
}
for (int col = 0; col < rowSource.LastCellNum; col++)
{
var cellsource = rowSource.GetCell(col);
var cellInsert = rowInsert.CreateCell(col);
var cellStyle = cellsource.CellStyle;
//设置单元格样式
if (cellStyle != null)
{
cellInsert.CellStyle = cellsource.CellStyle;
}
}
}
}
//绑定数据
for (int j = 0; j < txtPoints.Count; j++)
{
TxtPoint t = txtPoints[j];
IRow r = sheet.GetRow(j + 2);
r.Cells[0].SetCellValue(j + 1);
r.Cells[1].SetCellValue("江仓站");
r.Cells[9].SetCellValue(t.Bear);
r.Cells[10].SetCellValue(t.DeltaBear);
}
//sheet.GetRow
//后续操作
using (FileStream files = new FileStream(dir, FileMode.Create))
{
workbook.Write(files);
}
fs.Dispose();
}
catch(Exception ex)
{
XtraMessageBox.Show(ex.Message);
}
}
不仅出现下三行内容消失,新增的行高度和格式也不同
这真是个无解的问题
在我一筹莫展的过了一天,然后想到DevExpress有一个可视的报表软件SpreadSheetControl
方法二:解决了我之前的更改模板的问题,而且可以在不影响Header和Footer的情况下,在中间插入格式的N行,并且暂时没发现问题!Nice!
我是直接用的DevExpress的Template Gallery中的SpreadSheet
步骤如下
基本操作,选择项目
找到SpreadSheet就可以很方便啦
首先贴出一些常用的打开。保存。插入N行的代码
//打开文件操作
public static string OpenExcel()
{
OpenFileDialog fileDialog = new OpenFileDialog();
fileDialog.Multiselect = true;
fileDialog.Title = "请选择文件";
fileDialog.Filter = "所有文件(*.xls)|*.xls"; //设置要选择的文件的类型
if (fileDialog.ShowDialog() == DialogResult.OK)
{
return fileDialog.FileName;//返回文件的完整路径
}
else
{
return null;
}
}
//导入Excel
private void ImportData(string filePath)//导入按钮
{
if (!string.IsNullOrEmpty(filePath))
{
IWorkbook workbook = spreadsheetControl.Document;
workbook.LoadDocument(filePath);
}
}
//保存Excel文件
private void SaveExcel()
{
try
{
string s = GetDirectoryInfo(3).FullName + "副本CTCS_ExcelModel.xlsx";
spreadsheetControl.SaveDocument(s,DocumentFormat.Xlsx);
}
catch (Exception ExError)
{
XtraMessageBox.Show("该文件正被别的地方占用");
ExError.ToString();
}
}
public static DirectoryInfo GetDirectoryInfo(int index)
{
string directoryindex = "";
for (int i = 0; i < index; i++)
{
directoryindex += @"..\";
}
DirectoryInfo di = new DirectoryInfo(string.Format("{0}{1}", System.Windows.Forms.Application.StartupPath, directoryindex));
return di;
}
不过本来写了这些打开、导入方法,好像这个demo已经包含了这些功能
所以这些我就注释掉了
private void spreadsheetCommandBarButtonItem190_ItemClick(object sender, ItemClickEventArgs e)
{
//DirectoryInfo di = GetDirectoryInfo(3);
//string file = di.FullName + "CTCS_ExcelModel.xlsx";
//ImportExcel(file);
}
一些插入行和获取行列信息的代码
//访问行
Workbook workbook=new Workbook();
//Access a Collection of rows
RowCollection rows = workbook.Worksheets[0].Rows;
//Access the first row by its index in the collection of rows;
Row firstRow_byIndex = rows[0];
//Access ths first row by its unique name
Row firstRow_byName = rows["1"];
访问列
Workbook workbook=new Workbook();
//Access a collection of columns
ColumnCollection columns = workbook.Worksheets[0].Columns.
//ColumnCollection columns=workbook.Worksheets[0].Columns;
Column firstColumn_byIndex = columns[0];
//Access the first column by its unique name;
Column firstColumn_byName = columns["A"];//
一些更具体的使用方法来自如下:
https://blog.csdn.net/hotmee/article/details/50554381
接下来插入N行的思路是:先在指定位置添加Rows,这些Row是空白的无格式的,之后就需要CopyFrom,从现有行复制模板
这里要注意Insert(int index,int count);这里的index指的是,
/// <summary>
/// 插入N行
/// </summary>
/// <param name="workbook">Excel工作区</param>
/// <param name="sheetIndex">sheet索引</param>
/// <param name="startRowIndex">开始插入行的索引(向下插入表的)</param>
/// <param name="rowcount">插入的行数</param>
private void InsertRows(IWorkbook workbook,int sheetIndex,int startRowIndex,int rowcount)
{
Worksheet sheet = workbook.Worksheets[sheetIndex];
RowCollection rows = sheet.Rows;
//example:
//sheet.Rows.Insert(6, 5);//在行索引为6的行下方插入5行,即增加7、8、9、10、11
sheet.Rows.Insert(startRowIndex, rowcount);
for(int j=startRowIndex; j<startRowIndex+rowcount;j++)
{
sheet.Rows[j].CopyFrom(sheet.Rows[3]);//复制行格式
}
}
//使用方法//我在第6行下方添加了5行,并更改了格式
//InsertRows(spreadsheetControl.Document, 0,6,5);
图示:
插入5行
稍微更改了一下
加上了formatRow的index
/// <summary>
/// 插入N行
/// </summary>
/// <param name="workbook">Excel工作区</param>
/// <param name="sheetIndex">sheet索引</param>
/// <param name="startRowIndex">开始插入行的索引(向下插入表的)</param>
/// <param name="rowcount">插入的行数</param>
/// <param name="formatRowIndex">格式行的索引值</param>
private void InsertRows(IWorkbook workbook,int sheetIndex,int startRowIndex,int rowcount,int formatRowIndex)
{
Worksheet sheet = workbook.Worksheets[sheetIndex];
RowCollection rows = sheet.Rows;
//example:
//sheet.Rows.Insert(6, 5);//在行索引为6的行下方插入5行,即增加7、8、9、10、11
sheet.Rows.Insert(startRowIndex, rowcount);
for(int j=startRowIndex; j<startRowIndex+rowcount;j++)
{
sheet.Rows[j].CopyFrom(sheet.Rows[formatRowIndex-1]);//复制行格式
}
}
就成了复制第三行的样式
SpreadSheet合并和取消合并方法
//取消合并
sheet.UnMergeCells(sheet.Range[“D2:J2”]);、
//合并
sheet.MergeCells(sheet.Range[“D2:D3”]);
行删除
//更改cell的边框格式为OutLine
sheet.Cells[“D2”].Borders.SetOutsideBorders(Color.Black, BorderLineStyle.Medium);