如何使用 C# 附加现有 excel 文件
How to append existing excel file using C#
下面是我的代码,我无法在 excel 中附加内容,
第一次加载程序时,excel可以正常输出
但是在第二次加载程序时,excel 会严重崩溃(无法打开)。
我正在使用 FileMode.Append、FileAccess.Write,但仍然无法正常工作
有没有我错过的步骤?请帮我解决这个问题,非常感谢!
XSSFWorkbook XSSFworkbook = new XSSFWorkbook(); //建立活頁簿
ISheet sheet = XSSFworkbook.CreateSheet(tbx_Build.Text); //建立sheet
//設定樣式
ICellStyle headerStyle = XSSFworkbook.CreateCellStyle();
IFont headerfont = XSSFworkbook.CreateFont();
headerStyle.Alignment = HorizontalAlignment.Center; //水平置中
headerStyle.VerticalAlignment = VerticalAlignment.Center; //垂直置中
headerfont.FontName = "Segoe UI";
headerfont.FontHeightInPoints = 12;
headerfont.Boldweight = (short)FontBoldWeight.Bold;
headerStyle.SetFont(headerfont);
XSSFCellStyle cs = (XSSFCellStyle)XSSFworkbook.CreateCellStyle();
cs.WrapText = true; // 設定換行
cs.VerticalAlignment = NPOI.SS.UserModel.VerticalAlignment.Top;
//新增標題列
IRow headerrow = sheet.CreateRow(0);//建立行
headerrow.HeightInPoints = 20;
headerrow.CreateCell(0).SetCellValue("System_name");
headerrow.CreateCell(1).SetCellValue("Fixture_name");
headerrow.CreateCell(2).SetCellValue("build_ID");
headerrow.CreateCell(3).SetCellValue("start_time");
headerrow.CreateCell(4).SetCellValue("end_time");
headerrow.CreateCell(5).SetCellValue("serial_number");
headerrow.CreateCell(6).SetCellValue("Status");
headerrow.CreateCell(7).SetCellValue("Symptom_label");
headerrow.CreateCell(8).SetCellValue("Repair");
headerrow.CreateCell(9).SetCellValue("Measurement");
headerrow.CreateCell(10).SetCellValue("Board_slot");
headerrow.CreateCell(11).SetCellValue("Error");
headerrow.CreateCell(12).SetCellValue("Version");
for (int i = 0; i < 13; i++)
{
headerrow.GetCell(i).CellStyle = headerStyle; //套用樣式
}
//填入資料
int rowIndex = 1;
for (int i = 0; i < dt.Rows.Count; i++)
{
IRow row = sheet.CreateRow(rowIndex);//建立行
row.HeightInPoints = 18;
row.CreateCell(0).SetCellValue(Convert.ToString(dt.Rows[i]["System_name"]));
row.CreateCell(1).SetCellValue(Convert.ToString(dt.Rows[i]["Fixture_name"]));
row.CreateCell(2).SetCellValue(Convert.ToString(dt.Rows[i]["build_ID"]));
row.CreateCell(3).SetCellValue(Convert.ToString(dt.Rows[i]["start_time"]));
row.CreateCell(4).SetCellValue(Convert.ToString(dt.Rows[i]["end_time"]));
row.CreateCell(5).SetCellValue(Convert.ToString(dt.Rows[i]["serial_number"]));
row.CreateCell(6).SetCellValue(Convert.ToString(dt.Rows[i]["Status"]));
row.CreateCell(7).SetCellValue(Convert.ToString(dt.Rows[i]["Symptom_label"]));
row.CreateCell(8).SetCellValue(Convert.ToString(dt.Rows[i]["Repair"]));
row.CreateCell(9).SetCellValue(Convert.ToString(dt.Rows[i]["Measurement"]));
row.CreateCell(10).SetCellValue(Convert.ToString(dt.Rows[i]["Board_slot"]));
row.CreateCell(11).SetCellValue(Convert.ToString(dt.Rows[i]["Error"]));
row.CreateCell(12).SetCellValue(Convert.ToString(dt.Rows[i]["Version"]));
if (dt.Rows[i]["Error"].ToString().Contains("\n"))
{
row.GetCell(12).CellStyle = cs;
row.HeightInPoints = 45;
}
else if (dt.Rows[i]["Repair"].ToString().Contains("\n"))
{
row.GetCell(12).CellStyle = cs;
row.HeightInPoints = 45;
}
sheet.AutoSizeColumn(i); //欄位自動調整大小
rowIndex++;
}
string newName2 = "Yield.xlsx";
string exportpath2 = server_backup_failed + "\output";
if (!System.IO.Directory.Exists(exportpath2))
{
System.IO.Directory.CreateDirectory(exportpath2);//不存在就建立目錄
}
var file2 = new FileStream(exportpath2 + "\" + newName2, FileMode.Append, FileAccess.Write);
XSSFworkbook.Write(file2, true);
file2.Close();
XSSFworkbook.Close();
}
如前所述……我可以从一些测试中确认……
FileMode.Append
不会像您预期的那样工作。这似乎有些明显,因为一个工作簿可以有多个工作表,而您所描述的是将数据附加到现有工作表中……FileStream
将不知道如何执行此操作。
因此,如前所述,您需要打开文件,进行更改(追加行),然后保存并关闭文件。在我的测试中,这可以使用您的大部分代码进行一些小的更改。在您当前的代码中,它总是创建一个“新的”Excel 工作簿和工作表。因此,如果您想将某些内容“附加”到工作表,则这“意味着”工作簿和工作表可能已经存在。所以,如果工作簿已经存在,那么我们要打开它而不是创建一个新的。
因此,我建议采用一个小方法,该方法采用 string
文件路径和文件名以及 return 工作簿。如果工作簿存在,那么我们只需 return 工作簿。如果工作簿不存在,那么我们 return 一个“新”工作簿。如果路径错误或任何其他故障......我们将 return 一个 null
值。像……
private XSSFWorkbook GetExcelWorkbook(string filePath) {
if (!File.Exists(filePath)) {
return new XSSFWorkbook();
}
try {
using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) {
return new XSSFWorkbook(fs);
}
}
catch (Exception ex) {
Debug.WriteLine("Excel Error getting workbook: " + ex.Message);
return null;
}
}
这应该有助于获取工作簿。接下来,代码似乎正在寻找“特定”工作表。与上面的代码类似,一个简单的方法需要一个工作簿和一个工作表名称以及 returns 一个具有给定名称的工作表可能会派上用场。同样,如果工作表已经存在,那么我们只需 return 该工作表。如果工作表不存在,那么我们将创建一个具有给定名称的新工作表。此外,如果工作表是新的,我们将继续添加 headers 行。这也是另一种方法,因此您也可以在每次附加新数据时添加 header 行。但是,在此示例中,仅在创建新工作表时才添加 header,并假定 header 行已存在于现有文件中。
这个方法可能看起来像……
private ISheet GetWorksheet(XSSFWorkbook wb, string targetSheetName) {
try {
for (int i = 0; i < wb.NumberOfSheets; i++) {
if (wb.GetSheetAt(i).SheetName.Equals(targetSheetName)) {
return wb.GetSheetAt(i);
}
}
ISheet ws = wb.CreateSheet(targetSheetName);
AddHeaders(wb, ws);
return ws;
}
catch (Exception e) {
Debug.WriteLine("Excel Error getting worksheet: " + e.Message);
return null;
}
}
上面代码的演练很简单……循环遍历给定的工作簿工作表以查找目标工作表名称。如果找到工作表,它将被 returned。如果未找到工作表,则使用目标名称创建一个新工作表,将 header 添加到新工作表,然后将 return 添加到新工作表。如果出现错误,null
值是 returned。
接下来是将 header 添加到工作表的方法,几乎直接从您的代码中获取。
private void AddHeaders(XSSFWorkbook wb, ISheet sheet) {
IRow headerrow = sheet.CreateRow(0);
headerrow.HeightInPoints = 20;
headerrow.CreateCell(0).SetCellValue("System_name");
headerrow.CreateCell(1).SetCellValue("Fixture_name");
headerrow.CreateCell(2).SetCellValue("build_ID");
headerrow.CreateCell(3).SetCellValue("start_time");
headerrow.CreateCell(4).SetCellValue("end_time");
headerrow.CreateCell(5).SetCellValue("serial_number");
headerrow.CreateCell(6).SetCellValue("Status");
headerrow.CreateCell(7).SetCellValue("Symptom_label");
headerrow.CreateCell(8).SetCellValue("Repair");
headerrow.CreateCell(9).SetCellValue("Measurement");
headerrow.CreateCell(10).SetCellValue("Board_slot");
headerrow.CreateCell(11).SetCellValue("Error");
headerrow.CreateCell(12).SetCellValue("Version");
ICellStyle headerStyle = wb.CreateCellStyle();
IFont headerfont = wb.CreateFont();
headerStyle.Alignment = HorizontalAlignment.Center;
headerStyle.VerticalAlignment = VerticalAlignment.Center;
headerfont.FontName = "Segoe UI";
headerfont.FontHeightInPoints = 12;
headerfont.Boldweight = (short)FontBoldWeight.Bold;
headerStyle.SetFont(headerfont);
for (int i = 0; i < 13; i++) {
headerrow.GetCell(i).CellStyle = headerStyle;
}
}
这些方法应该可以简化将数据“附加”到现有工作表或创建新工作表的过程。因此,使用上述方法,下面的代码将按此处所述工作……此代码被添加到按钮点击事件中。最初,为将附加到工作表的 DataTable
dt
创建了一些测试数据。接下来,我们检查给定的文件夹路径是否存在,如果不存在,则创建它。
接下来我们使用上面的方法获取工作簿和工作表。工作表名称与您在当前代码中的名称相同,来自表单上的 TextBox
...tbx_Build
。
接下来,我们不将 rowIndex
设置为 1,而是将其设置为工作表中现有数据的最后一行,以便我们可以“追加”数据。具体来说……
int rowIndex = ws.LastRowNum + 1;
接下来创建单元格样式并循环遍历 DataTables
dt
行,其中每个单元格都添加到工作表中。请注意,我删除了不必要的“转换”代码并使用了单元格 ToString()
方法。最后出于某种原因将样式添加到某些单元格。
最后,创建 FilesStream
以保存文件并可能在文件不是新文件时覆盖它。
您可能会注意到,工作簿 wb
在 try/catch/finally
语句的 finally
部分关闭,原因是如果代码在工作簿之后的某个时间失败是打开的,那么它可能不会被关闭。这确保工作簿正确关闭。
private void button1_Click(object sender, EventArgs e) {
string workbookName = "__NewBook_1.xlsx";
string saveFilePath = @"D:\Test\Excel_Test";
DataTable dt = GetTable();
FillTable(dt);
XSSFWorkbook wb = null;
try {
if (!Directory.Exists(saveFilePath)) {
Directory.CreateDirectory(saveFilePath);
}
wb = GetExcelWorkbook(saveFilePath + @"\" + workbookName);
if (wb != null) {
ISheet ws = GetWorksheet(wb, tbx_Build.Text);
if (ws != null) {
int rowIndex = ws.LastRowNum + 1;
ICellStyle cs = wb.CreateCellStyle();
cs.WrapText = true;
cs.VerticalAlignment = VerticalAlignment.Top;
for (int i = 0; i < dt.Rows.Count; i++) {
IRow row = ws.CreateRow(rowIndex);
row.HeightInPoints = 18;
row.CreateCell(0).SetCellValue(dt.Rows[i]["System_name"].ToString());
row.CreateCell(1).SetCellValue(dt.Rows[i]["Fixture_name"].ToString());
row.CreateCell(2).SetCellValue(dt.Rows[i]["build_ID"].ToString());
row.CreateCell(3).SetCellValue(dt.Rows[i]["start_time"].ToString());
row.CreateCell(4).SetCellValue(dt.Rows[i]["end_time"].ToString());
row.CreateCell(5).SetCellValue(dt.Rows[i]["serial_number"].ToString());
row.CreateCell(6).SetCellValue(dt.Rows[i]["Status"].ToString());
row.CreateCell(7).SetCellValue(dt.Rows[i]["Symptom_label"].ToString());
row.CreateCell(8).SetCellValue(dt.Rows[i]["Repair"].ToString());
row.CreateCell(9).SetCellValue(dt.Rows[i]["Measurement"].ToString());
row.CreateCell(10).SetCellValue(dt.Rows[i]["Board_slot"].ToString());
row.CreateCell(11).SetCellValue(dt.Rows[i]["Error"].ToString());
row.CreateCell(12).SetCellValue(dt.Rows[i]["Version"].ToString());
if (dt.Rows[i]["Error"].ToString().Contains("\n")) {
row.GetCell(12).CellStyle = cs;
row.HeightInPoints = 45;
}
else if (dt.Rows[i]["Repair"].ToString().Contains("\n")) {
row.GetCell(12).CellStyle = cs;
row.HeightInPoints = 45;
}
ws.AutoSizeColumn(i);
rowIndex++;
}
using (FileStream fs = new FileStream(saveFilePath + @"\" + workbookName, FileMode.Create, FileAccess.Write)) {
wb.Write(fs, true);
}
}
}
}
catch (Exception ex) {
Debug.WriteLine("Excel Error: " + ex.Message);
}
finally {
if (wb != null) {
wb.Close();
}
}
}
最后是创建一些测试数据以测试上述方法并完成示例的代码。
using NPOI.SS.UserModel;
using NPOI.XSSF.UserModel;
using HorizontalAlignment = NPOI.SS.UserModel.HorizontalAlignment;
private DataTable GetTable() {
DataTable dt = new DataTable();
dt.Columns.Add("System_name");
dt.Columns.Add("Fixture_name");
dt.Columns.Add("build_ID");
dt.Columns.Add("start_time");
dt.Columns.Add("end_time");
dt.Columns.Add("serial_number");
dt.Columns.Add("Status");
dt.Columns.Add("Symptom_label");
dt.Columns.Add("Repair");
dt.Columns.Add("Measurement");
dt.Columns.Add("Board_slot");
dt.Columns.Add("Error");
dt.Columns.Add("Version");
return dt;
}
private void FillTable(DataTable dt) {
for (int i = 0; i < 20; i++) {
dt.Rows.Add("C0R" + (i + 1), "C1R" + (i + 1), "C2R" + (i + 1), "C3R" + (i + 1), "C4R" + (i + 1),
"C5R" + (i + 1), "C6R" + (i + 1), "C7R" + (i + 1), "C8R" + (i + 1), "C9R" + (i + 1),
"C10R" + (i + 1), "C11R" + (i + 1), "C12R" + (i + 1));
}
}
我希望这是有道理的。我对此进行了多次测试,它似乎按预期工作,但是可能仍然存在一些必要的异常检查,但为简洁起见未添加。如果有什么不正确的地方请告诉我,我会尽可能改正。
下面是我的代码,我无法在 excel 中附加内容, 第一次加载程序时,excel可以正常输出 但是在第二次加载程序时,excel 会严重崩溃(无法打开)。 我正在使用 FileMode.Append、FileAccess.Write,但仍然无法正常工作 有没有我错过的步骤?请帮我解决这个问题,非常感谢!
XSSFWorkbook XSSFworkbook = new XSSFWorkbook(); //建立活頁簿
ISheet sheet = XSSFworkbook.CreateSheet(tbx_Build.Text); //建立sheet
//設定樣式
ICellStyle headerStyle = XSSFworkbook.CreateCellStyle();
IFont headerfont = XSSFworkbook.CreateFont();
headerStyle.Alignment = HorizontalAlignment.Center; //水平置中
headerStyle.VerticalAlignment = VerticalAlignment.Center; //垂直置中
headerfont.FontName = "Segoe UI";
headerfont.FontHeightInPoints = 12;
headerfont.Boldweight = (short)FontBoldWeight.Bold;
headerStyle.SetFont(headerfont);
XSSFCellStyle cs = (XSSFCellStyle)XSSFworkbook.CreateCellStyle();
cs.WrapText = true; // 設定換行
cs.VerticalAlignment = NPOI.SS.UserModel.VerticalAlignment.Top;
//新增標題列
IRow headerrow = sheet.CreateRow(0);//建立行
headerrow.HeightInPoints = 20;
headerrow.CreateCell(0).SetCellValue("System_name");
headerrow.CreateCell(1).SetCellValue("Fixture_name");
headerrow.CreateCell(2).SetCellValue("build_ID");
headerrow.CreateCell(3).SetCellValue("start_time");
headerrow.CreateCell(4).SetCellValue("end_time");
headerrow.CreateCell(5).SetCellValue("serial_number");
headerrow.CreateCell(6).SetCellValue("Status");
headerrow.CreateCell(7).SetCellValue("Symptom_label");
headerrow.CreateCell(8).SetCellValue("Repair");
headerrow.CreateCell(9).SetCellValue("Measurement");
headerrow.CreateCell(10).SetCellValue("Board_slot");
headerrow.CreateCell(11).SetCellValue("Error");
headerrow.CreateCell(12).SetCellValue("Version");
for (int i = 0; i < 13; i++)
{
headerrow.GetCell(i).CellStyle = headerStyle; //套用樣式
}
//填入資料
int rowIndex = 1;
for (int i = 0; i < dt.Rows.Count; i++)
{
IRow row = sheet.CreateRow(rowIndex);//建立行
row.HeightInPoints = 18;
row.CreateCell(0).SetCellValue(Convert.ToString(dt.Rows[i]["System_name"]));
row.CreateCell(1).SetCellValue(Convert.ToString(dt.Rows[i]["Fixture_name"]));
row.CreateCell(2).SetCellValue(Convert.ToString(dt.Rows[i]["build_ID"]));
row.CreateCell(3).SetCellValue(Convert.ToString(dt.Rows[i]["start_time"]));
row.CreateCell(4).SetCellValue(Convert.ToString(dt.Rows[i]["end_time"]));
row.CreateCell(5).SetCellValue(Convert.ToString(dt.Rows[i]["serial_number"]));
row.CreateCell(6).SetCellValue(Convert.ToString(dt.Rows[i]["Status"]));
row.CreateCell(7).SetCellValue(Convert.ToString(dt.Rows[i]["Symptom_label"]));
row.CreateCell(8).SetCellValue(Convert.ToString(dt.Rows[i]["Repair"]));
row.CreateCell(9).SetCellValue(Convert.ToString(dt.Rows[i]["Measurement"]));
row.CreateCell(10).SetCellValue(Convert.ToString(dt.Rows[i]["Board_slot"]));
row.CreateCell(11).SetCellValue(Convert.ToString(dt.Rows[i]["Error"]));
row.CreateCell(12).SetCellValue(Convert.ToString(dt.Rows[i]["Version"]));
if (dt.Rows[i]["Error"].ToString().Contains("\n"))
{
row.GetCell(12).CellStyle = cs;
row.HeightInPoints = 45;
}
else if (dt.Rows[i]["Repair"].ToString().Contains("\n"))
{
row.GetCell(12).CellStyle = cs;
row.HeightInPoints = 45;
}
sheet.AutoSizeColumn(i); //欄位自動調整大小
rowIndex++;
}
string newName2 = "Yield.xlsx";
string exportpath2 = server_backup_failed + "\output";
if (!System.IO.Directory.Exists(exportpath2))
{
System.IO.Directory.CreateDirectory(exportpath2);//不存在就建立目錄
}
var file2 = new FileStream(exportpath2 + "\" + newName2, FileMode.Append, FileAccess.Write);
XSSFworkbook.Write(file2, true);
file2.Close();
XSSFworkbook.Close();
}
如前所述……我可以从一些测试中确认……
FileMode.Append
不会像您预期的那样工作。这似乎有些明显,因为一个工作簿可以有多个工作表,而您所描述的是将数据附加到现有工作表中……FileStream
将不知道如何执行此操作。
因此,如前所述,您需要打开文件,进行更改(追加行),然后保存并关闭文件。在我的测试中,这可以使用您的大部分代码进行一些小的更改。在您当前的代码中,它总是创建一个“新的”Excel 工作簿和工作表。因此,如果您想将某些内容“附加”到工作表,则这“意味着”工作簿和工作表可能已经存在。所以,如果工作簿已经存在,那么我们要打开它而不是创建一个新的。
因此,我建议采用一个小方法,该方法采用 string
文件路径和文件名以及 return 工作簿。如果工作簿存在,那么我们只需 return 工作簿。如果工作簿不存在,那么我们 return 一个“新”工作簿。如果路径错误或任何其他故障......我们将 return 一个 null
值。像……
private XSSFWorkbook GetExcelWorkbook(string filePath) {
if (!File.Exists(filePath)) {
return new XSSFWorkbook();
}
try {
using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) {
return new XSSFWorkbook(fs);
}
}
catch (Exception ex) {
Debug.WriteLine("Excel Error getting workbook: " + ex.Message);
return null;
}
}
这应该有助于获取工作簿。接下来,代码似乎正在寻找“特定”工作表。与上面的代码类似,一个简单的方法需要一个工作簿和一个工作表名称以及 returns 一个具有给定名称的工作表可能会派上用场。同样,如果工作表已经存在,那么我们只需 return 该工作表。如果工作表不存在,那么我们将创建一个具有给定名称的新工作表。此外,如果工作表是新的,我们将继续添加 headers 行。这也是另一种方法,因此您也可以在每次附加新数据时添加 header 行。但是,在此示例中,仅在创建新工作表时才添加 header,并假定 header 行已存在于现有文件中。
这个方法可能看起来像……
private ISheet GetWorksheet(XSSFWorkbook wb, string targetSheetName) {
try {
for (int i = 0; i < wb.NumberOfSheets; i++) {
if (wb.GetSheetAt(i).SheetName.Equals(targetSheetName)) {
return wb.GetSheetAt(i);
}
}
ISheet ws = wb.CreateSheet(targetSheetName);
AddHeaders(wb, ws);
return ws;
}
catch (Exception e) {
Debug.WriteLine("Excel Error getting worksheet: " + e.Message);
return null;
}
}
上面代码的演练很简单……循环遍历给定的工作簿工作表以查找目标工作表名称。如果找到工作表,它将被 returned。如果未找到工作表,则使用目标名称创建一个新工作表,将 header 添加到新工作表,然后将 return 添加到新工作表。如果出现错误,null
值是 returned。
接下来是将 header 添加到工作表的方法,几乎直接从您的代码中获取。
private void AddHeaders(XSSFWorkbook wb, ISheet sheet) {
IRow headerrow = sheet.CreateRow(0);
headerrow.HeightInPoints = 20;
headerrow.CreateCell(0).SetCellValue("System_name");
headerrow.CreateCell(1).SetCellValue("Fixture_name");
headerrow.CreateCell(2).SetCellValue("build_ID");
headerrow.CreateCell(3).SetCellValue("start_time");
headerrow.CreateCell(4).SetCellValue("end_time");
headerrow.CreateCell(5).SetCellValue("serial_number");
headerrow.CreateCell(6).SetCellValue("Status");
headerrow.CreateCell(7).SetCellValue("Symptom_label");
headerrow.CreateCell(8).SetCellValue("Repair");
headerrow.CreateCell(9).SetCellValue("Measurement");
headerrow.CreateCell(10).SetCellValue("Board_slot");
headerrow.CreateCell(11).SetCellValue("Error");
headerrow.CreateCell(12).SetCellValue("Version");
ICellStyle headerStyle = wb.CreateCellStyle();
IFont headerfont = wb.CreateFont();
headerStyle.Alignment = HorizontalAlignment.Center;
headerStyle.VerticalAlignment = VerticalAlignment.Center;
headerfont.FontName = "Segoe UI";
headerfont.FontHeightInPoints = 12;
headerfont.Boldweight = (short)FontBoldWeight.Bold;
headerStyle.SetFont(headerfont);
for (int i = 0; i < 13; i++) {
headerrow.GetCell(i).CellStyle = headerStyle;
}
}
这些方法应该可以简化将数据“附加”到现有工作表或创建新工作表的过程。因此,使用上述方法,下面的代码将按此处所述工作……此代码被添加到按钮点击事件中。最初,为将附加到工作表的 DataTable
dt
创建了一些测试数据。接下来,我们检查给定的文件夹路径是否存在,如果不存在,则创建它。
接下来我们使用上面的方法获取工作簿和工作表。工作表名称与您在当前代码中的名称相同,来自表单上的 TextBox
...tbx_Build
。
接下来,我们不将 rowIndex
设置为 1,而是将其设置为工作表中现有数据的最后一行,以便我们可以“追加”数据。具体来说……
int rowIndex = ws.LastRowNum + 1;
接下来创建单元格样式并循环遍历 DataTables
dt
行,其中每个单元格都添加到工作表中。请注意,我删除了不必要的“转换”代码并使用了单元格 ToString()
方法。最后出于某种原因将样式添加到某些单元格。
最后,创建 FilesStream
以保存文件并可能在文件不是新文件时覆盖它。
您可能会注意到,工作簿 wb
在 try/catch/finally
语句的 finally
部分关闭,原因是如果代码在工作簿之后的某个时间失败是打开的,那么它可能不会被关闭。这确保工作簿正确关闭。
private void button1_Click(object sender, EventArgs e) {
string workbookName = "__NewBook_1.xlsx";
string saveFilePath = @"D:\Test\Excel_Test";
DataTable dt = GetTable();
FillTable(dt);
XSSFWorkbook wb = null;
try {
if (!Directory.Exists(saveFilePath)) {
Directory.CreateDirectory(saveFilePath);
}
wb = GetExcelWorkbook(saveFilePath + @"\" + workbookName);
if (wb != null) {
ISheet ws = GetWorksheet(wb, tbx_Build.Text);
if (ws != null) {
int rowIndex = ws.LastRowNum + 1;
ICellStyle cs = wb.CreateCellStyle();
cs.WrapText = true;
cs.VerticalAlignment = VerticalAlignment.Top;
for (int i = 0; i < dt.Rows.Count; i++) {
IRow row = ws.CreateRow(rowIndex);
row.HeightInPoints = 18;
row.CreateCell(0).SetCellValue(dt.Rows[i]["System_name"].ToString());
row.CreateCell(1).SetCellValue(dt.Rows[i]["Fixture_name"].ToString());
row.CreateCell(2).SetCellValue(dt.Rows[i]["build_ID"].ToString());
row.CreateCell(3).SetCellValue(dt.Rows[i]["start_time"].ToString());
row.CreateCell(4).SetCellValue(dt.Rows[i]["end_time"].ToString());
row.CreateCell(5).SetCellValue(dt.Rows[i]["serial_number"].ToString());
row.CreateCell(6).SetCellValue(dt.Rows[i]["Status"].ToString());
row.CreateCell(7).SetCellValue(dt.Rows[i]["Symptom_label"].ToString());
row.CreateCell(8).SetCellValue(dt.Rows[i]["Repair"].ToString());
row.CreateCell(9).SetCellValue(dt.Rows[i]["Measurement"].ToString());
row.CreateCell(10).SetCellValue(dt.Rows[i]["Board_slot"].ToString());
row.CreateCell(11).SetCellValue(dt.Rows[i]["Error"].ToString());
row.CreateCell(12).SetCellValue(dt.Rows[i]["Version"].ToString());
if (dt.Rows[i]["Error"].ToString().Contains("\n")) {
row.GetCell(12).CellStyle = cs;
row.HeightInPoints = 45;
}
else if (dt.Rows[i]["Repair"].ToString().Contains("\n")) {
row.GetCell(12).CellStyle = cs;
row.HeightInPoints = 45;
}
ws.AutoSizeColumn(i);
rowIndex++;
}
using (FileStream fs = new FileStream(saveFilePath + @"\" + workbookName, FileMode.Create, FileAccess.Write)) {
wb.Write(fs, true);
}
}
}
}
catch (Exception ex) {
Debug.WriteLine("Excel Error: " + ex.Message);
}
finally {
if (wb != null) {
wb.Close();
}
}
}
最后是创建一些测试数据以测试上述方法并完成示例的代码。
using NPOI.SS.UserModel;
using NPOI.XSSF.UserModel;
using HorizontalAlignment = NPOI.SS.UserModel.HorizontalAlignment;
private DataTable GetTable() {
DataTable dt = new DataTable();
dt.Columns.Add("System_name");
dt.Columns.Add("Fixture_name");
dt.Columns.Add("build_ID");
dt.Columns.Add("start_time");
dt.Columns.Add("end_time");
dt.Columns.Add("serial_number");
dt.Columns.Add("Status");
dt.Columns.Add("Symptom_label");
dt.Columns.Add("Repair");
dt.Columns.Add("Measurement");
dt.Columns.Add("Board_slot");
dt.Columns.Add("Error");
dt.Columns.Add("Version");
return dt;
}
private void FillTable(DataTable dt) {
for (int i = 0; i < 20; i++) {
dt.Rows.Add("C0R" + (i + 1), "C1R" + (i + 1), "C2R" + (i + 1), "C3R" + (i + 1), "C4R" + (i + 1),
"C5R" + (i + 1), "C6R" + (i + 1), "C7R" + (i + 1), "C8R" + (i + 1), "C9R" + (i + 1),
"C10R" + (i + 1), "C11R" + (i + 1), "C12R" + (i + 1));
}
}
我希望这是有道理的。我对此进行了多次测试,它似乎按预期工作,但是可能仍然存在一些必要的异常检查,但为简洁起见未添加。如果有什么不正确的地方请告诉我,我会尽可能改正。