You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

导出DataSet至Excel时出现多余空白工作表的原因排查

问题根源&修复方案

嘿,我帮你拆解下这两个问题的来龙去脉,都是代码里的小细节踩坑了:

一、多余空白Sheet4的来历

你这空白表其实是两处操作叠加出来的:

  1. 初始工作簿自带空白表:调用xl.Workbooks.Add()的时候,Excel默认会给你创建一个带1个空白工作表(默认叫Sheet1)的工作簿,这是第一个“种子”空白表。
  2. WriteToExcel里的错误添加操作:每次写完一个DataTable到工作表后,你执行了xl.Worksheets.Add(sheet);——这个方法会在你当前处理的工作表前面插入一个全新的空白工作表。你循环处理3个表,就会额外插3个空白表,但前两个空白表被后续循环覆盖写入了数据,最后插的那个Sheet4没被用到,就留成了空白表。

二、工作表顺序颠倒的原因

你的DataSet里表的添加顺序是CombinedNon-ServicesServices,foreach也是按这个顺序循环的,但每次处理时:

  • 你都拿当前工作簿的第一个工作表xl.ActiveWorkbook.Sheets[1])来写数据,写完又在它前面插新空白表。
  • 这就导致后处理的表反而被挤到了前面,比如最后处理的Services被放在了Non-Services前面,最终顺序完全反过来了。

修复后的代码(直接能用)

我把MSClass的逻辑改了下,核心是每次写数据时创建新工作表,而不是复用旧表插空白表,同时保证顺序正确:

class MSClass
{
    static Microsoft.Office.Interop.Excel.Application xl;
    static Microsoft.Office.Interop.Excel.Workbook workbook; // 直接存工作簿引用,避免反复查找

    public static void CreateExcelFile()
    {
        xl = new Excel.Application();
        workbook = xl.Workbooks.Add();
        // 删掉初始自带的空白工作表,避免残留
        if (workbook.Sheets.Count > 0)
        {
            ((Excel.Worksheet)workbook.Sheets[1]).Delete();
        }
    }

    public static void SaveExcelFile(string filePath)
    {
        if (!string.IsNullOrEmpty(filePath))
        {
            try
            {
                xl.DisplayAlerts = false;
                workbook.SaveAs(filePath); // 保存整个工作簿,不是单个工作表
                xl.Visible = true;
            }
            catch (Exception ex)
            {
                throw new Exception("Export To Excel: Excel file could not be saved! Check filePath.\n" + ex.Message);
            }
        }
        else
        {
            xl.Visible = true;
        }
    }

    public static void WriteToExcel(DataTable table, string sheetName)
    {
        // 新建工作表,直接加到工作簿的最后,保证顺序和DataSet一致
        Excel.Worksheet sheet = (Excel.Worksheet)workbook.Sheets.Add(After: workbook.Sheets[workbook.Sheets.Count]);
        sheet.Name = sheetName;

        int colCount = table.Columns.Count;
        object[] header = new object[colCount];
        for (int i = 0; i < colCount; i++)
        {
            header[i] = table.Columns[i].ColumnName;
        }

        Excel.Range headerRange = sheet.get_Range(sheet.Cells[1, 1], sheet.Cells[1, colCount]);
        headerRange.Value = header;
        headerRange.Interior.Color = ColorTranslator.ToOle(Color.LightGray);
        headerRange.Font.Bold = true;

        int rowCount = table.Rows.Count;
        if (rowCount > 0)
        {
            object[,] cells = new object[rowCount, colCount];
            for (int j = 0; j < rowCount; j++)
            {
                for (int i = 0; i < colCount; i++)
                {
                    cells[j, i] = table.Rows[j][i];
                }
            }
            sheet.get_Range(sheet.Cells[2, 1], sheet.Cells[rowCount + 1, colCount]).Value = cells;
        }
    }
}

关键修改点说下:

  • 加了workbook变量直接存工作簿,不用每次查找,更稳定;
  • 创建工作簿后直接删掉初始空白表,从根上避免残留;
  • 每次写数据时新建工作表并加到工作簿最后,这样DataSet里的表顺序和Excel里的工作表顺序完全一致;
  • 保存时改成保存整个工作簿,之前的代码只保存了激活的单个工作表,其实是有隐患的。

如果之后你想调整工作表顺序,直接改DataSet里表的添加顺序,或者倒序遍历DataSet.Tables就行。

内容的提问来源于stack exchange,提问作者Jaskier

火山引擎 最新活动