别的不多说,直接上干货
在NPOI中没有delete删除的方法,有的只是ShiftRows()这个方法,这个方法是指将某行至某行的内容上下移动,这个方法拥有3个参数;第一个参数和第二个参数是指移动的行下标,也就是我要将一个参数行到第二个参数行的内容做移动;例如sheet.ShifRows(2,8,1);表达的就是我将第2行到第8行的内容向下移动一行;显然这里的第三个参数1就是指往上还是往下移动多少,正数为向下移动,负数为向上移动,数值为移动多少行。
那么为什么要说ShifRows这个方法呢,因为我们进行删除是靠它实现的,当我们比如说要删除sheet表中第7行数据,那么我们就可以把第8行到最后一行的数据往上移动一行,这样第7行数据就被覆盖了,也就实现了第7行的删除。这里我用一个小demo给大家演示一下:
删除前:
进行删除:
下面贴出代码:
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace DeleteRow
{
public partial class Form1 : Form
{
XSSFWorkbook wk;
ISheet sheet;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
if( openFileDialog1.ShowDialog()==DialogResult.OK)
{
using (FileStream fs=new FileStream(openFileDialog1.FileName, FileMode.Open, FileAccess.ReadWrite))
{
wk = new XSSFWorkbook(fs);
sheet = wk.GetSheetAt(0);
label1.Text = "删除的行数(最大为" + sheet.LastRowNum + ")";
MessageBox.Show("打开Excel文件成功!");
}
}
}
private void button2_Click(object sender, EventArgs e)
{
sheet.ShiftRows(Convert.ToInt32(textBox1.Text),sheet.LastRowNum,-1);
output();
}
private void output()
{
if (saveFileDialog1.ShowDialog() == DialogResult.OK)
{
MemoryStream bookStream = new MemoryStream();
wk.Write(bookStream);
var buf = bookStream.ToArray();
using (FileStream fs = new FileStream(saveFileDialog1.FileName, FileMode.Create, FileAccess.Write))
{
fs.Write(buf,0,buf.Length);
fs.Flush();
fs.Close();
}
MessageBox.Show("生成成功!");
}
}
}
}
很多细心的朋友可能会注意到,我输入的删除第6行,那不应该是sheet.ShiftRows(7,lastNum,-1)吗,这里第一个参数确实是第7行,但是第7行的索引下标为6,所以删除第6行,实际是sheet.ShiftRows(6,lastNum,-1),上文那么说只是为了大家方便理解。
另外需要提到的点是这里的XSSFWorkbook与ISheet需要去Nuget上引入NPOI的dll包,记住版本要是2.4.1或以前的,因为较新的版本在进行删除时会对Excel文件损坏。
那么可以删除一行结束,接下来是我们关注的重点——删除带合并表格的行,为什么这个问题单独提出来,因为在进行删除时,有合并表格会出现删除错位的情况,如下:
图中出现合并表格,现在我们进行删除:
细心的同学会发现,我们把第十行删除了,但是原本第九行是正常的,现在跑到了合并单元格中,并且后面的都变成了j,本来应该是k往往在项目中遇到这类问题非常头疼,以下是解决方案:
///
/// 判断表的某行是否有合并,有则删除合并
///
///
///
public void IsMergeRow(int rowIndex, ref ISheet mergeSheet)
{
for (int i = 0; i < mergeSheet.NumMergedRegions; i++)
{
CellRangeAddress range = mergeSheet.GetMergedRegion(i);
if (range == null)
{
return;
}
if (rowIndex >= range.FirstRow && range.LastRow >= rowIndex)
{
mergeSheet.RemoveMergedRegion(i);
}
}
}
上面这段代码是检测传入的行是否包含合并单元格,如果包含,则去掉合并。
那在删除之前调用这个方法则可以达到想删除带有合并单元格的行的目的:
在点击删除的地方调用代码:
private void button2_Click(object sender, EventArgs e)
{
IsMergeRow(Convert.ToInt32(textBox1.Text),ref sheet);
sheet.ShiftRows(Convert.ToInt32(textBox1.Text),sheet.LastRowNum,-1);
output();
}
这个方法可以看见解除合并单元格后并没有复原,所以如果要想复原,那么操作便是 解除合并——>删除——>合并,在这里我就不列出来了,合并方法:
代码:sheet.AddMergedRegion(new CellRangeAddress(0, 1, 0, 0));
CellRangeAddress有4个参数:起始行号,终止行号, 起始列号,终止列号
注意:
1.起始行号 不可能大于 终止行号(错误:new CellRangeAddress(1, 0, 0, 0))。
2.起始列号 不可能大于 终止列号(错误:new CellRangeAddress(0, 0, 1, 0))。
3.execl的行列都是从0开始,而不是从1开始。
希望分享对读者有帮助!