Как мне в С# изменить электронную таблицу Excel, сохранить ее под другим именем и удалить исходную электронную таблицу

У меня есть приложение Windows Form, которое дает пользователю открытое диалоговое окно для открытия электронной таблицы.

Приложение выполняет некоторые задачи в этой электронной таблице, такие как сортировка и удаление пустых строк. Затем, когда он закончен, он выполняет SaveAs, используя текущую дату как часть нового имени файла.

После этого я хочу удалить исходную таблицу.

Я использую Microsoft.Office.Interop.Excel.

Я нашел код здесь, в StackOverflow (Как правильно очистить объекты взаимодействия Excel ?), который показывает, как закрыть Excel, а третий ответ в этом сообщении от nightcoder даже показал способ (который я использую), который удалит Excel с вкладки «Процессы» диспетчера задач.

Я думал, что как только Excel будет сброшен из диспетчера задач, он снимет свою мертвую хватку, похожую на ледяную щупальце, с файлом, который я пытаюсь закрыть, но как же я ошибался.

Когда код попадает в команду File.Delete(MyFile), он все еще говорит, что я не могу удалить этот файл, потому что на нем мертвая хватка, похожая на ледяную щупальце, или что-то в этом роде.

Кто-нибудь знает, где я могу найти бейсбольную биту, достаточно большую, чтобы приложение отпустило файл. Я бы очень хотел удалить его.

================================================== ============
22.07.2013 Обновление

Вот часть моего кода, который у меня есть до сих пор.

Этот код позволяет пользователю выбрать электронную таблицу 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();
        }
        //=========================================================================================================================================
        //=========================================================================================================================================
        //=========================================================================================================================================
    }
}

person Robert Lawson    schedule 27.06.2013    source источник


Ответы (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);

Вы сохраняете копию предыдущего имени файла и удаляете его.

ПРЕДУПРЕЖДЕНИЕ. Поскольку вы не предоставили отдельный пример, я не смог его протестировать. Также вы можете отредактировать это, чтобы удалять только в случае успешного сохранения и если имя файла отличается от исходного имени файла.

person BlueTrin    schedule 14.07.2014