serbanov Ответов: 2

C# открыть excel для чтения ошибки


Привет,

Не знаю почему, но я не могу открыть файл excel.

Это мой код:
private void button2_Click(object sender, EventArgs e)
{
    Excel.Workbook xlWorkBook;
    Excel.Worksheet xlWorkSheet;

    object misValue = System.Reflection.Missing.Value;

    Excel.Application xlApp = new Excel.Application();

    if (xlApp == null)
    {
        MessageBox.Show("Excel is not properly installed!!");
        return;
    }

    xlApp = new Excel.Application();
    xlWorkBook = xlApp.Workbooks.Open(textBox1.Text, 0, true, 5, "", "", true, Excel.XlPlatform.xlWindows, "\t", false, false, 0, true, 1, 0);
    xlWorkSheet= (Excel.Worksheet)xlWorkBook.Worksheets.get_Item(1);


    int _countcolumns = xlWorkSheet.Cells.Find(
                "*",
                System.Reflection.Missing.Value,
                System.Reflection.Missing.Value,
                System.Reflection.Missing.Value,
                Excel.XlSearchOrder.xlByColumns,
                Excel.XlSearchDirection.xlPrevious,
                false,
                System.Reflection.Missing.Value,
                System.Reflection.Missing.Value).Column;

    int _lastrow = xlWorkSheet.Cells.Find(
                                    "*",
                                    System.Reflection.Missing.Value,
                                    Excel.XlFindLookIn.xlValues,
                                    Excel.XlLookAt.xlWhole,
                                    Excel.XlSearchOrder.xlByRows,
                                    Excel.XlSearchDirection.xlPrevious,
                                    false,
                                    System.Reflection.Missing.Value,
                                    System.Reflection.Missing.Value).Row;

    xlWorkBook.Close(true, null, null);
    xlApp.Quit();

    System.Runtime.InteropServices.Marshal.ReleaseComObject(xlWorkSheet);
    System.Runtime.InteropServices.Marshal.ReleaseComObject(xlWorkBook);
    System.Runtime.InteropServices.Marshal.ReleaseComObject(xlApp);

    MessageBox.Show("Last column used" + _countcolumns.ToString() + " and last row: " + _lastrow.ToString());
}

private void button1_Click(object sender, EventArgs e)
{
    string path;
    OpenFileDialog file = new OpenFileDialog();
    if (file.ShowDialog() == DialogResult.OK)
    {

        path = file.FileName;
        textBox1.Text = path;
    }
}



Я получаю ошибку
System.Runtime.InteropServices.COMException (0x80010105)
. Он указывает на строку, в которой я пытаюсь открыть файл Excel.




РЕДАКТИРОВАТЬ ****** :

xlWorkBook = xlApp.Workbooks.Open(textBox1.Text, 0, true, 5, "", "", true, Microsoft.Office.Interop.Excel.XlPlatform.xlWindows, "\t", false, false, 0, true, 1, Microsoft.Office.Interop.Excel.XlCorruptLoad.xlExtractData);


Since i have over 4k cells with different format style and few cells with maybe over 200 chars , that was the best solution for me. Hope someone will find it useful !


Что я уже пробовал:

Несколько советов я нашел в интернете, но ни один не сработал.

2 Ответов

Рейтинг:
8

#realJSOP

Вот класс, который я написал для загрузки файлов Excel. Он компилируется и работает так, как задумано (я думаю, что использую Interop v15, но это не должно иметь никакого влияния на этот код), не стесняйтесь изменять его в соответствии с вашими требованиями:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using Excel = Microsoft.Office.Interop.Excel;

/*
    Usage:
        string filename = System.IO.Path.Combine(BODCommon.Globals.MyDocuments, "alliedhealth_20140701143001275.xlsx");
        ExcelInterop ei = new ExcelInterop(filename);
        List<string> sheets = ei.GetSheetNames();
        // ...
        // Do something with the spreadsheet
        // ...
        ei.Close();
*/
namespace ExcelFunctions
{
    public static class WinAPI
    {
        [DllImport("user32.dll")]
        public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
    }

    public class ExcelInterop
    {

        private Excel.Application excelApp = new Excel.Application();
        protected bool        IsLoaded { get; set; }
        protected string      FileName { get; set; }
        public Excel.Workbook Workbook { get ; set; }

        public ExcelInterop(string fileName)
        {
            this.IsLoaded = false;
            // the excel app is opened when this class is instantiated.
            this.FileName = fileName;
            this.Load();
        }

        public void Close()
        {
            try
            {
                uint iProcessID;
                WinAPI.GetWindowThreadProcessId((IntPtr)excelApp.Hwnd, out iProcessID);

                this.Workbook.Close(0, Missing.Value, Missing.Value);
                this.excelApp.Quit();

                System.Diagnostics.Process[] processes = System.Diagnostics.Process.GetProcessesByName("Excel");
                System.Diagnostics.Process process = processes.Where(x=>x.Id == iProcessID).FirstOrDefault();
                if (process != null)
                {
                    process.Kill();
                }
            }
            catch (Exception ex)
            {
            }
        }

        /// <summary>
        /// Loads the file specified in the constructor. If the file is a XLS file, it is converted 
        /// to XLSX. If the new filename already exists, the filename is adjust with "_0n" 
        /// depending on how many copies of the file exists.
        /// </summary>
        protected void Load()
        {
            if (string.IsNullOrEmpty(this.FileName))
            {
                throw new InvalidOperationException("Filename not specified.");
            }
            if (!File.Exists(this.FileName))
            {
                throw new InvalidOperationException(string.Format("File ({0}) not found.", this.FileName));
            }
            this.ConvertXlsToXlsx();
            this.Workbook = this.excelApp.Workbooks.Open(this.FileName, AddToMru:false);
            this.IsLoaded = true;
        }

        private void CheckLoaded()
        {
            if (!this.IsLoaded)
            {
                throw new Exception("File has not been loaded.");
            }
        }

        /// <summary>
        ///  Gets a list of worksheet names in the currently loaded workbook
        /// </summary>
        /// <returns></returns>
        public List<string> GetSheetNames()
        {
            this.CheckLoaded();
            List<string> names = new List<string>();
            {
                for (int i = 1; i <= this.Workbook.Sheets.Count; i++)
                {
                    names.Add(this.Workbook.Sheets[i].Name);
                }
            }
            return names;
        }

        /// <summary>
        /// Gets the active worksheet in the currently loaded workbook.
        /// </summary>
        /// <param name="name"></param>
        public void ActivateWorksheet(string name)
        {
            this.CheckLoaded();
            Excel._Worksheet worksheet = (Excel._Worksheet)(this.Workbook.Sheets[name]);
            worksheet.Activate();
        }

        #region used cell range methods

        /// <summary>
        /// Gets the used cell range for the currently active worksheet
        /// </summary>
        /// <returns></returns>
        public Excel.Range GetUsedRange()
        {
            this.CheckLoaded();
            Excel._Worksheet sheet = ((Excel._Worksheet)(this.Workbook.ActiveSheet));
            if (sheet == null)
            {
                throw new Exception("Active worksheet not set.");
            }
            Excel.Range usedRange = sheet.UsedRange;
            return usedRange;
        }

        /// <summary>
        /// Gets the used cell range for the named worksheet
        /// </summary>
        /// <param name="sheetName"></param>
        /// <returns></returns>
        public Excel.Range GetUsedRange(string sheetName)
        {
            this.CheckLoaded();
            Excel._Worksheet sheet = ((Excel._Worksheet)(this.Workbook.Sheets[sheetName]));
            if (sheet == null)
            {
                throw new Exception(string.Format("Named worksheet ({0}) not found.", sheetName));
            }
            Excel.Range usedRange = sheet.UsedRange;
            return usedRange;
        }

        /// <summary>
        /// Gets the used columns in the currently active worksheet
        /// </summary>
        /// <returns></returns>
        public Excel.Range GetUsedColumns()
        {
            Excel.Range usedRange = this.GetUsedRange();
            return usedRange.Columns;
        }

        /// <summary>
        /// Gets the used columns in the named worksheet
        /// </summary>
        /// <param name="sheetName"></param>
        /// <returns></returns>
        public Excel.Range GetUsedColumns(string sheetName)
        {
            Excel.Range usedRange = this.GetUsedRange(sheetName);
            return usedRange.Columns;
        }

        /// <summary>
        /// Gets the used rows in the currently active worksheet
        /// </summary>
        /// <returns></returns>
        public Excel.Range GetUsedRows()
        {
            Excel.Range usedRange = this.GetUsedRange();
            return usedRange.Rows;
        }

        /// <summary>
        /// Gets the used rows in the named worksheet
        /// </summary>
        /// <param name="sheetName"></param>
        /// <returns></returns>
        public Excel.Range GetUsedRows(string sheetName)
        {
            Excel.Range usedRange = this.GetUsedRange(sheetName);
            return usedRange.Rows;
        }

        #endregion used cell range methods

        /// <summary>
        /// Converts the file from xls to xlsx by loading the xls, and then saving it in the 
        /// appropriate format, and with an "x" at the end of the extension. If the xlsx file 
        /// already exists, the filename will contain a version serial number (001-999) 
        /// indicating the newest version of the file. This method is called by the Load 
        /// method.
        /// </summary>
        public void ConvertXlsToXlsx()
        {
            if (this.FileName.ToUpper().EndsWith(".xls"))
            {
                string path = System.IO.Path.GetDirectoryName(this.FileName);
                string filename = System.IO.Path.GetFileNameWithoutExtension(this.FileName);

                string newName = string.Empty;
                string version = string.Empty;
                int count = 0;
                do
                {
                    newName = System.IO.Path.Combine(path, string.Concat(filename, version, ".xlsx"));
                    if (File.Exists(newName))
                    {
                        count++;
                        version = string.Format((count > 99) ? "_{0:000}" : "_{0:00}", count);
                    }
                    else
                    {
                        break;
                    }
                } while (true);
                this.FileName = newName;

                var workbook = this.excelApp.Workbooks.Open(this.FileName);
                workbook.SaveAs(Filename: this.FileName, FileFormat: Excel.XlFileFormat.xlOpenXMLWorkbook, AddToMru:false);
                workbook.Close();
            }
        }

        public string SaveSheetAsFile(string sheetName)
        {
            Excel._Worksheet sheet = this.Workbook.Sheets[sheetName];
            string filename = string.Empty;

            if (sheet != null)
            {
                filename = this.BuildFileName(sheetName);
                if (File.Exists(filename))
                {
                    File.Delete(filename);
                }
                // create a new workbook
                var newbook = this.excelApp.Workbooks.Add(1);
                // copy the desired sheet into it
                sheet.Copy(newbook.Sheets[1]);
                // delete the 2nd sheet
                newbook.Sheets[2].Delete();
                newbook.SaveAs(filename, FileFormat:Excel.XlFileFormat.xlWorkbookDefault, AddToMru:false);
                newbook.Close();
            }
            return filename;
        }

        private string BuildFileName(string sheetName)
        {
            string path = System.IO.Path.GetDirectoryName(this.FileName);
            string filename = System.IO.Path.GetFileNameWithoutExtension(this.FileName);
            string extension = System.IO.Path.GetExtension(this.FileName);
            filename = string.Format("{0} - {1}{2}", filename, sheetName, extension);
        


serbanov

Здравствуйте, В понедельник я попробую это сделать на работе и приду с ответом. Может быть, потому, что он видит interop 12, и я пытаюсь добавить ссылку interop 14.0, это будет проблемой ?

#realJSOP

Вы должны добавить ссылку на нужную версию сборки. У меня на рабочем компьютере есть две версии-14 и 15.

Michael_Davies

Даже если вы выходите из Excel, он остается запущенным в фоновом режиме, если вы не сделали его видимым (excelApp. Visible=true), поскольку он имеет активное COM-соединение с вашим приложением, лучший способ-освободить COM-объект и очистить память, а не найти процесс и убить его;

В То Время Как Система.Во время выполнения.InteropServices.Маршал.ReleaseComObject (Excel)< & gt; 0
Приложение.Функция doevents()
Конец Пока

К сожалению, это в VB ни один конвертер кода не преобразует его.

serbanov

Я видел, что Excel все еще работает, потому что я поставил свойство Visible на true ... я не знаю, что мне делать .. действительно...

Michael_Davies

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

#realJSOP

Я просто убиваю соответствующий процесс Excel (см. Мой метод Close). Это тоже заботится о нем.

Michael_Davies

Кувалдой расколоть орех. У вас уже есть ссылка на приложение, нет необходимости получать PID, затем получить все копии Excel, которые работают в массиве, и найти копию, на которую у вас уже есть ссылка, а затем убить ее, аккуратно...

#realJSOP

Если кувалда делает свою работу, и у вас есть один под рукой, нет никакого смысла рыться в ящике, чтобы найти крекер. Я хотел убедиться, что процесс мертв. Как дверной гвоздь. Кроме того, были сообщения о том, что вызов ReleaseComObject не всегда работает, но что убийство процесса *всегда работает. В любом случае, мой метод работает просто отлично.

serbanov

Microsoft.Офис.Взаимодействие.Excel. XlCorruptLoad. xlExtractData-это решило проблему, похоже, что office <= 2007, если он имеет более 4k ячеек, отформатированных по-разному, или более 255 символов в ячейке, он становится поврежденным .. теперь он отлично работает с этим параметром в рабочей книге метода.Открыть()

Рейтинг:
16

Michael_Davies

Есть ли у вас привилегия доступа к файлу Excel?

Не вижу, как вы получаете имя файла в текстовое поле, но если все, что находится в текстовом поле, - это имя без пути, это может не сработать, попробуйте использовать OpenFileDialog, чтобы быть уверенным в точном пути и имени.


serbanov

У меня нет привилегии доступа к файлу Excel, я получаю имя в текстовое поле с помощью private void button1_Click(Object sender, EventArgs e), который открывает мне OpenFileDialog, и я выбираю excel, который хочу открыть.

Michael_Davies

Если у вас нет такой привилегии, то вы не можете открыть файл, просто так.

serbanov

Извините, я неправильно понял то, что вы сказали... У меня есть привилегия открыть его, так как у меня есть права администратора, и я уже создавал его раньше .

xlWorkBook.Сохранить как(generatePath.Текст + "xLExcel.xls", Excel.XlFileFormat.xlWorkbookNormal, misValue, misValue, misValue, misValue, в формате Excel.XlSaveAsAccessMode.xlExclusive, misValue, misValue, misValue, misValue, misValue);

Вот как я его генерирую!

Michael_Davies

Итак, вы можете проверить значение в текстовом поле

serbanov

Да, значение в моем текстовом поле таково: "D:\xlExcel_old4.xls - так что, думаю, все в порядке ... это файл, который я даю в качестве входных данных

Michael_Davies

К сожалению, имена этих двух файлов не совпадают...
Создать: generatePath.Текст + "xLExcel.xls"
Открыть: D:\xlExcel_old4.xls

serbanov

Да, потому что я его переименовал ??? Я сгенерировал еще несколько версий,а старые переименовал.

serbanov

Кстати, я использую interop 14.0 !