如何在C#中修改Excel电子表格,将其另存为其他名称并删除原始电子表格

时间:2013-06-27 19:23:59

标签: c# excel visual-studio-2008 excel-interop

我有一个Windows窗体应用程序,它为用户提供一个打开的对话框来打开电子表格。

应用程序在该电子表格上执行一些任务,例如排序和删除空白行。然后,当它完成时,它使用当前日期作为新文件名的一部分执行SaveAs。

完成后我想要删除原始电子表格。

我正在使用Microsoft.Office.Interop.Excel。

我在StackOverflow(How do I properly clean up Excel interop objects?)上找到了代码,它显示了如何关闭Excel以及夜间编码器在该帖子中的第3个答案甚至显示了一种方法(我正在使用)将从“进程”选项卡中删除Excel任务经理。

我曾经以为Excel从任务管理器中被抛弃了,它会删除它像我试图关闭的文件那样冰冷的类似帐篷的死亡抓地力,但我有多么错误。

当代码命中File.Delete(MyFile)命令时,它仍然说我无法删除这个文件,因为它上面有一个冰冷的类似触手的死亡夹子或类似的东西。

有谁知道我在哪里可以找到足够大的棒球棒,让应用程序放开文件。我真的想删除它。

=============================================== ===============
2013年7月22日更新

到目前为止,这是我的代码的一部分。

此代码的作用是允许用户选择Excel电子表格,打开它,重命名然后关闭它。我删除了一些操纵电子表格的代码,我觉得这是不必要的。

我想要做的是在保存重命名的文件后关闭原始文件,打开重命名并退出应用程序,同时打开重命名的电子表格以进行任何进一步编辑。

目前它没有这样做。它只会使用新名称创建电子表格,然后同时关闭应用和电子表格。然后我必须手动打开新的电子表格。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Runtime.InteropServices;
using Excel = Microsoft.Office.Interop.Excel;
using System.Diagnostics;
using Microsoft.Office.Interop.Excel; 

namespace Weekly_Stats_Organizer
{
    public partial class Form1 : Form
    {
        [DllImport("user32.dll")]
        private static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);

        string _ExcelFileName;

        private string ExcelFileName
        {
            get { return _ExcelFileName; }
            set { _ExcelFileName = value; }
        }
        private string DefaultPath = "C:\\My Documents\\Weekly Stats";

        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            Stream FileName = null;
            OpenFileDialog OpenExcelSpreadsheet = new OpenFileDialog();
            OpenExcelSpreadsheet.InitialDirectory = DefaultPath;
            OpenExcelSpreadsheet.Filter = "Excel 2003 (*.xls)|*.xls|Excel 2007 (*.xlsx)|*.xlsx";
            OpenExcelSpreadsheet.FilterIndex = 1;
            OpenExcelSpreadsheet.RestoreDirectory = true;
            if(OpenExcelSpreadsheet.ShowDialog() == DialogResult.OK)
            {
                if((FileName = OpenExcelSpreadsheet.OpenFile()) != null)
                {
                    ExcelFileName = ((System.Windows.Forms.FileDialog)(OpenExcelSpreadsheet)).FileName;
                    GenerateWorkbook();
                }
            }
        }

        private void GetExcel()
        {

            Excel.Application ExcelApp = null;
            Excel.Workbook ExcelWorkBook = null;
            Excel.Sheets ExcelSheets = null;
            Excel.Worksheet MySheet = null;
            try
            {

                DateTime CurrentDate = DateTime.Today;
                string FileName = DefaultPath + "\\" + CurrentDate.Year.ToString() + "-" + CurrentDate.Month.ToString("D2") + "-" + CurrentDate.Day.ToString("D2") + " Weekly Stats.xls";

                ExcelApp = new Excel.Application();
                ExcelApp.Visible = false;
                ExcelWorkBook = ExcelApp.Workbooks.Open(ExcelFileName, 0, true, 5, "", "", false, Excel.XlPlatform.xlWindows, "", true, false, 0, true, false, false);

                ExcelSheets = ExcelWorkBook.Worksheets;

                MySheet = (Excel.Worksheet)ExcelSheets.get_Item("Sheet 1");

                ExcelWorkBook.SaveAs(FileName, Excel.XlFileFormat.xlWorkbookNormal, "", "", false, false,
                    Excel.XlSaveAsAccessMode.xlNoChange, Excel.XlSaveConflictResolution.xlUserResolution, true, "", "", "");

                //GC.Collect();
                //GC.WaitForPendingFinalizers();

                Marshal.ReleaseComObject(MySheet);
                Marshal.ReleaseComObject(ExcelSheets);

                MySheet = null;
                ExcelSheets = null;

                ExcelWorkBook.Close(false, System.Reflection.Missing.Value, System.Reflection.Missing.Value);
            }
            finally
            {
                Marshal.ReleaseComObject(ExcelWorkBook);

                int hWnd = ExcelApp.Application.Hwnd;
                TryKillProcessByMainWindowHwnd(hWnd);

                Marshal.ReleaseComObject(ExcelApp);
                ExcelWorkBook = null;
                ExcelApp = null;

                //if (File.Exists(ExcelFileName))
                //    File.Delete(ExcelFileName);

                System.Windows.Forms.Application.Exit();

            }


        }

        //=========================================================================================================================================
        //=========================================================================================================================================
        //=========================================================================================================================================
        // This code was found at https://stackoverflow.com/questions/158706/how-to-properly-clean-up-excel-interop-objects
        // is the answer provided by nightcoder.  This solution seems to be the only one that actually clears the Excel instance out of the 
        // Processes in Windows Task Manager.  The idea is to completely shut down Excel so that I can delete the original spreadsheet.  So far not
        // working out so well.
        private void GenerateWorkbook()
        {
          try
          {
              GetExcel();
          }
          finally
          {
            GC.Collect();
            GC.WaitForPendingFinalizers();
          }
        }

        //=============================================================================================================================================
        /// <summary> Tries to find and kill process by hWnd to the main window of the process.</summary>
        /// <param name="hWnd">Handle to the main window of the process.</param>
        /// <returns>True if process was found and killed. False if process was not found by hWnd or if it could not be killed.</returns>
        public static bool TryKillProcessByMainWindowHwnd(int hWnd)
        {
            uint processID;
            GetWindowThreadProcessId((IntPtr)hWnd, out processID);
            if (processID == 0) return false;
            try
            {
                Process.GetProcessById((int)processID).Kill();
            }
            catch (ArgumentException)
            {
                return false;
            }
            catch (Win32Exception)
            {
                return false;
            }
            catch (NotSupportedException)
            {
                return false;
            }
            catch (InvalidOperationException)
            {
                return false;
            }
            return true;
        }

        /// <summary> Finds and kills process by hWnd to the main window of the process.</summary>
        /// <param name="hWnd">Handle to the main window of the process.</param>
        /// <exception cref="ArgumentException">
        /// Thrown when process is not found by the hWnd parameter (the process is not running). 
        /// The identifier of the process might be expired.
        /// </exception>
        /// <exception cref="Win32Exception">See Process.Kill() exceptions documentation.</exception>
        /// <exception cref="NotSupportedException">See Process.Kill() exceptions documentation.</exception>
        /// <exception cref="InvalidOperationException">See Process.Kill() exceptions documentation.</exception>
        public static void KillProcessByMainWindowHwnd(int hWnd)
        {
            uint processID;
            GetWindowThreadProcessId((IntPtr)hWnd, out processID);
            if (processID == 0)
                throw new ArgumentException("Process has not been found by the given main window handle.", "hWnd");
            Process.GetProcessById((int)processID).Kill();
        }
        //=========================================================================================================================================
        //=========================================================================================================================================
        //=========================================================================================================================================
    }
}

1 个答案:

答案 0 :(得分:1)

你有这个代码的地方:

       ExcelWorkBook.SaveAs(FileName, Excel.XlFileFormat.xlWorkbookNormal, "", "", false, false,
            Excel.XlSaveAsAccessMode.xlNoChange, Excel.XlSaveConflictResolution.xlUserResolution, true, "", "", "");

尝试插入此代码:

       string oldFileName = ExcelWorkBook.FullName;
       ExcelWorkBook.SaveAs(FileName, Excel.XlFileFormat.xlWorkbookNormal, "", "", false, false,
            Excel.XlSaveAsAccessMode.xlNoChange, Excel.XlSaveConflictResolution.xlUserResolution, true, "", "", "");
       File.Delete(oldFileName);

您保留以前文件名的副本并将其删除。

警告:由于您没有提供独立示例,我无法对此进行测试。此外,您可能希望编辑此选项以仅在保存成功且文件名与原始文件名不同时才删除。