使用C#向现有的Excel文件追加数据

4

我对C#比较新,正在尝试将一些来自用户填写的DataGridView中的数据导出到Excel文件中。

目前,我的程序可以创建一个名为给定日期的Excel文件,同时与之相关的DataGridView值。

我的问题是,如果Excel文件已经存在,我似乎找不到一种方法来追加来自gridview的数据,它会覆盖当前的Excel文件。

非常感谢任何帮助/提示/建议。

谢谢 :)

这是我的代码:

Microsoft.Office.Interop.Excel.Application xlApp;          
Microsoft.Office.Interop.Excel.Workbook xlWorkBook; 
Microsoft.Office.Interop.Excel.Worksheet xlWorkSheet;
Microsoft.Office.Interop.Excel.Sheets xlBigSheet;
Microsoft.Office.Interop.Excel.Sheets xlSheet;
object misValue;
String newPath;

private void buttonOK_Click(object sender, EventArgs e)
{
    createXLSfile();
}

private void createXLSfile(){
    String cDate = datePicker.Value.ToShortDateString();
    String cMonth = datePicker.Value.ToString("MMMM");
    String cYear = datePicker.Value.ToString("yy");
    String cDay = datePicker.Value.ToString("dd");

    String fName = cDay + "-" + cMonth+ "-" + cYear + ".xls";

    String mainPath = @"C:\Users\User1\Desktop\" + cYear;
    String folderPath = System.IO.Path.Combine(mainPath, cMonth);
    String excelPath = System.IO.Path.Combine(folderPath, fName);

    System.IO.Directory.CreateDirectory(mainPath);
    System.IO.Directory.CreateDirectory(folderPath);

    String fNameOnly = Path.GetFileNameWithoutExtension(excelPath);
    String extension = Path.GetExtension(excelPath);
    String path = Path.GetDirectoryName(excelPath);
    newPath = excelPath;

    if(File.Exists(newPath))
    {
        existingFile();
    }else
    {
        newFile();
    }
    MessageBox.Show("Submitted");
}

private void newFile()
{
    xlApp = new Microsoft.Office.Interop.Excel.Application();
    xlApp.Visible = true;
    misValue = System.Reflection.Missing.Value;
    xlWorkBook = xlApp.Workbooks.Add(misValue);
    xlWorkSheet = (Microsoft.Office.Interop.Excel.Worksheet)xlWorkBook.Worksheets.get_Item(1);

    xlWorkSheet = xlWorkBook.Sheets["Sheet1"];
    xlWorkSheet = xlWorkBook.ActiveSheet;
    xlWorkSheet.Name = "Sheet1";

    xlWorkSheet.Cells[2, 1] = "Header1";
    xlWorkSheet.Cells[2, 2] = "Header2";
    xlWorkSheet.Cells[2, 3] = "Total";
    getData();

    xlWorkBook.SaveAs(newFullPath, Microsoft.Office.Interop.Excel.XlFileFormat.xlWorkbookNormal, misValue,
    misValue, misValue, misValue, Microsoft.Office.Interop.Excel.XlSaveAsAccessMode.xlExclusive, misValue, misValue, misValue, misValue, misValue);
    xlWorkBook.Close(true, misValue, misValue);
    xlApp.Quit();
    Marshal.ReleaseComObject(xlWorkSheet);
    Marshal.ReleaseComObject(xlWorkBook);
    Marshal.ReleaseComObject(xlApp);
}

private void existingFile()
{
    xlApp = new Microsoft.Office.Interop.Excel.Application();
    xlApp.Visible = true;
    xlWorkBook = xlApp.Workbooks.Open(newPath, 0, 
                false, 5, "", "", false, Microsoft.Office.Interop.Excel.XlPlatform.xlWindows,
                 "", true, false, 0, true, false, false);

    xlBigSheet = xlWorkBook.Worksheets;
    string x = "Sheet1";
    xlWorkSheet = (Microsoft.Office.Interop.Excel.Worksheet)xlBigSheet.get_Item(x);

    getData();

    xlWorkBook.SaveAs(newPath, Microsoft.Office.Interop.Excel.XlFileFormat.xlWorkbookNormal,
            misValue, misValue, misValue, misValue, Microsoft.Office.Interop.Excel.XlSaveAsAccessMode.xlExclusive,
            misValue, misValue, misValue,
            misValue, misValue);

    xlWorkBook.Close(misValue, misValue, misValue);
    xlWorkBook = null;
    xlApp.Quit();
    GC.WaitForPendingFinalizers();
    GC.Collect();
    GC.WaitForPendingFinalizers();
    GC.Collect();
}

private void getData()
{
    double a,b,c,d,total = 0;
    int lastRow_ = 3;

    foreach(DataGridViewRow r in dataGridView1.Rows)
    {
        if(!r.IsNewRow)
        {
            a = Convert.ToDouble(r.Cells[2].Value);
            b = Convert.ToDouble(r.Cells[3].Value);
            c = Convert.ToDouble(r.Cells[4].Value);
            d = Convert.ToDouble(r.Cells[5].Value);

            total = a + b + c + d;

            xlWorkSheet.Cells[lastRow_, 1] = "Hi";
            xlWorkSheet.Cells[lastRow_, 2] = "Hello";
            xlWorkSheet.Cells[lastRow_, 3] = Convert.ToString(total);
            lastRow_ = xlWorkSheet.Cells.Find(
                        "*",
                        xlWorkSheet.Cells[1, 1],
                        misValue,
                        Microsoft.Office.Interop.Excel.XlLookAt.xlPart,
                        Microsoft.Office.Interop.Excel.XlSearchOrder.xlByRows,
                        Microsoft.Office.Interop.Excel.XlSearchDirection.xlPrevious,
                        misValue,
                        misValue,
                        misValue).Row + 1;
        }
    }
    total = 0;
}

更新1: 仍然卡住了。 一直在尝试跟随这个链接: https://www.codeproject.com/articles/5123/opening-and-navigating-excel-with-c 输出结果: 输出的Excel文件目录 这是输出的Excel文件里面的内容

你当前发布的代码中有几个问题无法编译,因此我对你能否将“DataGridView”导出到新的Excel文件表示怀疑。这一行:“String mainPath = "@C:\Users\User1\Desktop"" + cYear;”是不正确的... “@”放错了位置,而且末尾多了一个引号... 应该是“String mainPath = @"C:\Users\User1\Desktop" + cYear;”。另外,这一行:“System.IO.Directory.Create(folderPath);”也是不正确的,因为“Create”不存在... 应该是:“System.IO.Directory.CreateDirectory(mainPath);”。最后,为了帮助您... - JohnG
在调试创建Excel文件时,您可能想要添加以下代码行:xlApp.Visible = true;。这将允许您逐步查看代码中正在发生的情况,并可能揭示您遇到的一些问题。只是一个想法。 - JohnG
@JohnG 感谢您的帮助,这只是我在这里创建的一个模拟代码,因为我的主程序太大了。我的目录没有问题,我已经按照您说的做了。它覆盖了 Excel 文件,而不是将其附加到文件中。您有什么建议吗? - DisplayName
让我看看我是否理解正确。由于您的主程序代码太大而无法发布...所以您遇到问题的部分...您没有复制/粘贴代码,而是重新输入了它以创建带有错误的“模拟”版本?那么我之前指出的错误实际上不在您的代码中?如果是这种情况,那么为什么要浪费别人的时间呢?发布未能正常工作的代码(而不是“模拟”版本)。否则,对于您发布的“模拟”代码,答案是...它存在错误,而且它不能工作,因为它是“模拟”代码,其他人试图调试它或帮助您找到错误是毫无意义的。 - JohnG
你所发布的代码不可能运行,因为getData()方法中存在编译错误。 - JohnG
显示剩余3条评论
1个回答

7

当您需要将数据追加到现有工作表时,您需要找出最后一个使用的行在哪里,并在此行之后开始添加数据。您当前的代码获取“last”行是很笨拙的,因为一旦您开始添加行,您就会不断检查这个“last”行,这是不必要的。 getData() 方法只是在新的 Excel 文件中添加数据,在那里最后一行并不重要。如果文件存在,则只需获取最后使用的行并从下一行开始导入数据。我猜您的代码可能更好地发送起始行索引给GetData(RowToStart)方法,并简单地增加lastRow_变量,如下所示:没有必要一直检查最后一行。

private void getData(int lastRow_) {
  double a, b, c, d, total = 0;
  //int lastRow_ = 4;

  foreach (DataGridViewRow r in dataGridView1.Rows) {
    //if (!row.IsNewRow) {
    if (!r.IsNewRow) {
        a = Convert.ToDouble(r.Cells[2].Value);
      b = Convert.ToDouble(r.Cells[3].Value);
      c = Convert.ToDouble(r.Cells[4].Value);
      d = Convert.ToDouble(r.Cells[5].Value);

      total = a + b + c + d;

      xlWorkSheet.Cells[lastRow_, 1] = "Hi";
      xlWorkSheet.Cells[lastRow_, 2] = "Hello";
      xlWorkSheet.Cells[lastRow_, 3] = Convert.ToString(total);
      lastRow_++;
      //lastRow_ = xlWorkSheet.Cells.Find(
      //            "*",
      //            xlWorkSheet.Cells[1, 1],
      //            misValue,
      //            Microsoft.Office.Interop.Excel.XlLookAt.xlPart,
      //            Microsoft.Office.Interop.Excel.XlSearchOrder.xlByRows,
      //            Microsoft.Office.Interop.Excel.XlSearchDirection.xlPrevious,
      //            misValue,
      //            misValue,
      //            misValue).Row + 1;
    }
  }
  total = 0;
}

如果文件是新的,您需要像下面这样调用此方法。
 .
 .
 .
  xlWorkSheet.Cells[3, 1] = "Header1";
  xlWorkSheet.Cells[3, 2] = "Header2";
  xlWorkSheet.Cells[3, 3] = "Total";
  getData(4);
 .
 .
 .

如果文件已经存在,您需要将数据追加到现有工作表中,则需要获取最后使用的行,然后从下一行开始。您可以像下面这样调用 getData(RowToStart)
 .
 .
 .

 xlWorkSheet = (Microsoft.Office.Interop.Excel.Worksheet)xlBigSheet.get_Item("Sheet1");
 Microsoft.Office.Interop.Excel.Range last = xlWorkSheet.Cells.SpecialCells(Microsoft.Office.Interop.Excel.XlCellType.xlCellTypeLastCell, Type.Missing);
 int lastUsedRow = last.Row;
 getData(lastUsedRow + 1);
 .
 .
 .

我希望你能理解这个意思。

哇,非常感谢,它运作了。也谢谢您容忍我的提问:) 最后一个问题抱歉...您知道如何使Excel中的“字段名称....已存在于此位置。您要替换它吗?”不再出现吗?谢谢 - DisplayName
如果您不想看到覆盖对话框,您可以在Excel中关闭“DisplayAlerts”,如下所示:xlApp.DisplayAlerts = false; - JohnG

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接