web-dev-qa-db-fra.com

Comment lire les données d'un fichier Excel avec C #?

Comment lire un fichier Excel en C #? J'ouvre un fichier Excel pour le lire et le copie dans le presse-papier pour rechercher le format de courrier électronique, mais je ne sais pas comment le faire.

FileInfo finfo;
Excel.ApplicationClass ExcelObj = new Excel.ApplicationClass();
ExcelObj.Visible = false;

Excel.Workbook theWorkbook;
Excel.Worksheet worksheet;

if (listView1.Items.Count > 0)
{
    foreach (ListViewItem s in listView1.Items)
    {
        finfo = new FileInfo(s.Text);
        if (finfo.Extension == ".xls" || finfo.Extension == ".xlsx" || finfo.Extension == ".xlt" || finfo.Extension == ".xlsm" || finfo.Extension == ".csv")
        {
            theWorkbook = ExcelObj.Workbooks.Open(s.Text, 0, true, 5, "", "", true, Excel.XlPlatform.xlWindows, "\t", false, false, 0, true, false, false);

            for (int count = 1; count <= theWorkbook.Sheets.Count; count++)
            {
                worksheet = (Excel.Worksheet)theWorkbook.Worksheets.get_Item(count);
                worksheet.Activate();
                worksheet.Visible = false;
                worksheet.UsedRange.Cells.Select();
            }
        }
    }
}
61
ankush

D'ACCORD,

L'un des concepts les plus difficiles à comprendre sur la programmation Excel VSTO est que vous ne faites pas référence à des cellules comme un tableau, Worksheet[0][0] ne vous donnera pas la cellule A1, elle vous trompera. Même lorsque vous tapez dans A1 lorsque Excel est ouvert, vous entrez des données dans la plage A1. Par conséquent, vous vous référez aux cellules en tant que plages nommées. Voici un exemple:

Excel.Worksheet sheet = workbook.Sheets["Sheet1"] as Excel.Worksheet; 
Excel.Range range = sheet.get_Range("A1", Missing.Value)

Vous pouvez maintenant taper littéralement:

range.Text // this will give you the text the user sees
range.Value2 // this will give you the actual value stored by Excel (without rounding)

Si vous voulez faire quelque chose comme ça:

Excel.Range range = sheet.get_Range("A1:A5", Missing.Value)

if (range1 != null)
     foreach (Excel.Range r in range1)
     {
         string user = r.Text
         string value = r.Value2

     }

Il pourrait y avoir une meilleure façon, mais cela a fonctionné pour moi.

Si vous devez utiliser Value2 et non Value, c'est parce que la propriété Value est paramétrée et que C # ne les prend pas encore en charge.

En ce qui concerne le code de nettoyage, je le posterai quand je serai au travail demain, je n'ai pas le code avec moi, mais c'est très passe-partout. Vous venez de fermer et de libérer les objets dans l'ordre inverse de leur création. Vous ne pouvez pas utiliser un bloc Using() car Excel.Application ou Excel.Workbook n'implémente pas IDisposable. Si vous ne nettoyez pas, vous aurez un objet Excel suspendu en mémoire.

Remarque:

  • Si vous ne définissez pas la propriété Visibility, Excel ne s'affiche pas, ce qui peut être déconcertant pour vos utilisateurs, mais si vous souhaitez simplement extraire les données, cela suffit probablement.
  • Vous pourriez OleDb, cela fonctionnera aussi.

J'espère que cela vous aide à commencer, faites-moi savoir si vous avez besoin de précisions. Je posterai un complet 

voici un exemple complet:

using System;
using System.IO;
using System.Reflection;
using NUnit.Framework;
using ExcelTools = Ms.Office;
using Excel = Microsoft.Office.Interop.Excel;

namespace Tests
{
    [TestFixture]
    public class ExcelSingle
    {
        [Test]
        public void ProcessWorkbook()
        {
            string file = @"C:\Users\Chris\Desktop\TestSheet.xls";
            Console.WriteLine(file);

            Excel.Application Excel = null;
            Excel.Workbook wkb = null;

            try
            {
                Excel = new Excel.Application();

                wkb = ExcelTools.OfficeUtil.OpenBook(Excel, file);

                Excel.Worksheet sheet = wkb.Sheets["Data"] as Excel.Worksheet;

                Excel.Range range = null;

                if (sheet != null)
                    range = sheet.get_Range("A1", Missing.Value);

                string A1 = String.Empty;

                if( range != null )
                    A1 = range.Text.ToString();

                Console.WriteLine("A1 value: {0}", A1);

            }
            catch(Exception ex)
            {
                //if you need to handle stuff
                Console.WriteLine(ex.Message);
            }
            finally
            {
                if (wkb != null)
                    ExcelTools.OfficeUtil.ReleaseRCM(wkb);

                if (Excel != null)
                    ExcelTools.OfficeUtil.ReleaseRCM(Excel);
            }
        }
    }
}

Je posterai les fonctions d'ExcelTools demain, je n'ai pas ce code avec moi non plus.

Edit: Comme promis, voici les fonctions d’ExcelTools dont vous pourriez avoir besoin.

public static Excel.Workbook OpenBook(Excel.Application excelInstance, string fileName, bool readOnly, bool editable,
        bool updateLinks) {
        Excel.Workbook book = excelInstance.Workbooks.Open(
            fileName, updateLinks, readOnly,
            Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing,
            Type.Missing, editable, Type.Missing, Type.Missing, Type.Missing,
            Type.Missing, Type.Missing);
        return book;
    }

public static void ReleaseRCM(object o) {
        try {
            System.Runtime.InteropServices.Marshal.ReleaseComObject(o);
        } catch {
        } finally {
            o = null;
        }
    }

Pour être franc, ces choses sont beaucoup plus faciles si vous utilisez VB.NET. C'est en C # parce que je ne l'ai pas écrit. VB.NET fait bien les paramètres d'option, pas C #, d'où le Type.Missing. Une fois que vous avez tapé Type. Deux fois de suite, vous courez crier de la pièce!

Quant à votre question, vous pouvez essayer de suivre:

http://msdn.Microsoft.com/en-us/library/Microsoft.office.interop.Excel.range.find(VS.80).aspx

Je posterai un exemple quand je reviens de ma réunion ... bravo

Edit: Voici un exemple

range = sheet.Cells.Find("Value to Find",
                                                 Type.Missing,
                                                 Type.Missing,
                                                 Type.Missing,
                                                 Type.Missing,
                                                 Excel.XlSearchDirection.xlNext,
                                                 Type.Missing,
                                                 Type.Missing, Type.Missing);

range.Text; //give you the value found

Voici un autre exemple inspiré par ce site :

 range = sheet.Cells.Find("Value to find", Type.Missing, Type.Missing,Excel.XlLookAt.xlWhole,Excel.XlSearchOrder.xlByColumns,Excel.XlSearchDirection.xlNext,false, false, Type.Missing);

Cela aide à comprendre les paramètres.

P.S. Je suis l'une de ces personnes étranges qui aime apprendre l'automatisation COM. Tout ce code provient d'un outil que j'ai écrit pour le travail et qui m'a obligé à traiter plus de 1000 feuilles de calcul du laboratoire chaque lundi.

85
Chris

Vous pouvez utiliser Microsoft.Office.Interop.Excel Assembly pour traiter des fichiers Excel. 

  1. Faites un clic droit sur votre projet et allez à Add reference. Ajoutez le Microsoft.Office.Interop.Excel Assembly. 
  2. Inclure using Microsoft.Office.Interop.Excel; pour utiliser Assembly.

Voici l exemple de code: 

    using Microsoft.Office.Interop.Excel;

    //create the Application object we can use in the member functions.
    Microsoft.Office.Interop.Excel.Application _excelApp = new Microsoft.Office.Interop.Excel.Application();
    _excelApp.Visible = true;

    string fileName = "C:\\sampleExcelFile.xlsx";

    //open the workbook
    Workbook workbook = _excelApp.Workbooks.Open(fileName,
        Type.Missing, Type.Missing, Type.Missing, Type.Missing,
        Type.Missing, Type.Missing, Type.Missing, Type.Missing,
        Type.Missing, Type.Missing, Type.Missing, Type.Missing,
        Type.Missing, Type.Missing);

    //select the first sheet        
    Worksheet worksheet = (Worksheet)workbook.Worksheets[1];

    //find the used range in worksheet
    Range excelRange = worksheet.UsedRange;

    //get an object array of all of the cells in the worksheet (their values)
    object[,] valueArray = (object[,])excelRange.get_Value(
                XlRangeValueDataType.xlRangeValueDefault);

    //access the cells
    for (int row = 1;  row <= worksheet.UsedRange.Rows.Count; ++row)
    {
        for (int col = 1; col <= worksheet.UsedRange.Columns.Count; ++col)
        {
            //access each cell
            Debug.Print(valueArray[row, col].ToString());
        }
    }

    //clean up stuffs
    workbook.Close(false, Type.Missing, Type.Missing);
    Marshal.ReleaseComObject(workbook);

    _excelApp.Quit();
    Marshal.FinalReleaseComObject(_excelApp);
21
Green goblin

Pourquoi ne créez-vous pas OleDbConnection? Il existe de nombreuses ressources disponibles sur Internet. Voici un exemple

OleDbConnection con = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source="+filename+";Extended Properties=Excel 8.0");
con.Open();
try
{
     //Create Dataset and fill with imformation from the Excel Spreadsheet for easier reference
     DataSet myDataSet = new DataSet();
     OleDbDataAdapter myCommand = new OleDbDataAdapter(" SELECT * FROM ["+listname+"$]" , con);
     myCommand.Fill(myDataSet);
     con.Close();
     richTextBox1.AppendText("\nDataSet Filled");

     //Travers through each row in the dataset
     foreach (DataRow myDataRow in myDataSet.Tables[0].Rows)
     {
          //Stores info in Datarow into an array
          Object[] cells = myDataRow.ItemArray;
          //Traverse through each array and put into object cellContent as type Object
          //Using Object as for some reason the Dataset reads some blank value which
          //causes a hissy fit when trying to read. By using object I can convert to
          //String at a later point.
          foreach (object cellContent in cells)
          {
               //Convert object cellContect into String to read whilst replacing Line Breaks with a defined character
               string cellText = cellContent.ToString();
               cellText = cellText.Replace("\n", "|");
               //Read the string and put into Array of characters chars
               richTextBox1.AppendText("\n"+cellText);
          }
     }
     //Thread.Sleep(15000);
}
catch (Exception ex)
{
     MessageBox.Show(ex.ToString());
     //Thread.Sleep(15000);
}
finally
{
     con.Close();
}

Tout d’abord, il est important de savoir ce que vous entendez par "ouvrez un fichier Excel pour le lire et copiez-le dans le presse-papiers ..."

Ceci est très important car vous pouvez le faire de nombreuses façons en fonction de ce que vous avez l’intention de faire. Laisse-moi expliquer:

  1. Si vous voulez lire un ensemble de données et le copier dans le presse-papiers et que vous connaissez le format de données (par exemple, les noms de colonnes), je vous suggère d'utiliser un OleDbConnection pour ouvrir le fichier. Ainsi, vous pourrez traiter le fichier xls. contenu en tant que table de base de données, vous pouvez donc lire les données avec l'instruction SQL et les traiter comme vous le souhaitez.

  2. Si vous souhaitez effectuer des opérations sur les données avec le modèle d'objet Excel, ouvrez-les comme vous avez commencé.

  3. Il est parfois possible de traiter un fichier xls comme une sorte de fichier csv. Il existe des outils tels que File Helpers qui vous permettent de traiter et d’ouvrir un fichier xls de manière simple en mappant une structure sur un objet quelconque.

Un autre point important concerne la version Excel du fichier.

J'ai malheureusement, je le dis, une solide expérience de la bureautique sous toutes ses formes, même si elle est liée à des concepts tels que l'automatisation des applications, la gestion des données et les plug-ins. En général, je ne suggère qu'en dernier recours d'utiliser l'automatisation Excel ou Office. lire des données; juste s'il n'y a pas de meilleures façons d'accomplir cette tâche.

Travailler avec l'automatisation peut être lourd en performance, en termes de coût des ressources, pourrait impliquer d'autres problèmes liés par exemple à la sécurité et plus, et enfin et surtout, travailler avec COM interop n'est pas si "gratuit" .. Donc, ma suggestion est de réfléchir et d’analyser la situation en fonction de vos besoins, puis de prendre le meilleur moyen.

5
Hoghweed
try
        {
            DataTable sheet1 = new DataTable("Excel Sheet");
            OleDbConnectionStringBuilder csbuilder = new OleDbConnectionStringBuilder();
            csbuilder.Provider = "Microsoft.ACE.OLEDB.12.0";
            csbuilder.DataSource = fileLocation;
            csbuilder.Add("Extended Properties", "Excel 12.0 Xml;HDR=YES");
            string selectSql = @"SELECT * FROM [Sheet1$]";
            using (OleDbConnection connection = new OleDbConnection(csbuilder.ConnectionString))
            using (OleDbDataAdapter adapter = new OleDbDataAdapter(selectSql, connection))
            {
                connection.Open();
                adapter.Fill(sheet1);
            }
        }
        catch (Exception e)
        {
            Console.WriteLine(e.Message);
        }

Cela a fonctionné pour moi. S'il vous plaît essayez-le et laissez-moi savoir pour les questions.

4
Vishal Kotak

Utilisez OLEDB Connection pour communiquer avec des fichiers Excel. ça donne un meilleur résultat

using System.Data.OleDb;



                string physicalPath = "Your Excel file physical path";
                OleDbCommand cmd = new OleDbCommand();
                OleDbDataAdapter da = new OleDbDataAdapter();
                DataSet ds = new DataSet();
                String strNewPath = physicalPath;
                String connString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + strNewPath + ";Extended Properties=\"Excel 12.0;HDR=Yes;IMEX=2\"";
                String query = "SELECT * FROM [Sheet1$]"; // You can use any different queries to get the data from the Excel sheet
                OleDbConnection conn = new OleDbConnection(connString);
                if (conn.State == ConnectionState.Closed) conn.Open();
                try
                {
                    cmd = new OleDbCommand(query, conn);
                    da = new OleDbDataAdapter(cmd);
                    da.Fill(ds);

                }
                catch
                {
                    // Exception Msg 

                }
                finally
                {
                    da.Dispose();
                    conn.Close();
                }

Les données de sortie seront stockées dans un ensemble de données. Cet objet vous permet d’accéder facilement aux données.

1
Suganth G

Lecteur et graveur de fichiers Excel sans Excel sur votre système

  • Téléchargez et ajoutez la dll pour NPOI u'r project.
  • Utiliser ce code pour lire un fichier Excel.

            using (FileStream file = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
            {
               XSSFWorkbook XSSFWorkbook = new XSSFWorkbook(file);
            }
            ISheet objxlWorkSheet = XSSFWorkbook.GetSheetAt(0);
            int intRowCount = 1;
            int intColumnCount = 0;
            for (; ; )
            {
                IRow Row = objxlWorkSheet.GetRow(intRowCount);
                if (Row != null)
                {
                    ICell Cell = Row.GetCell(0);
                    ICell objCell = objxlWorkSheet.GetRow(intRowCount).GetCell(intColumnCount); }}
    
0
RandyMohan

Utilisez Open XML .

Voici un code pour traiter une feuille de calcul avec un nom d’onglet ou de feuille spécifique et la transférer au format CSV. (J'ai choisi un tuyau au lieu d'une virgule).

J'aimerais qu'il soit plus facile d'obtenir la valeur d'une cellule, mais je pense que c'est ce qui nous tient le plus à cœur. Vous pouvez voir que je fais référence aux documents MSDN où j'ai obtenu la plupart de ce code. C'est ce que Microsoft recommande.

    /// <summary>
    /// Got code from: https://msdn.Microsoft.com/en-us/library/office/gg575571.aspx
    /// </summary>
    [Test]
    public void WriteOutExcelFile()
    {
        var fileName = "ExcelFiles\\File_With_Many_Tabs.xlsx";
        var sheetName = "Submission Form"; // Existing tab name.
        using (var document = SpreadsheetDocument.Open(fileName, isEditable: false))
        {
            var workbookPart = document.WorkbookPart;
            var sheet = workbookPart.Workbook.Descendants<Sheet>().FirstOrDefault(s => s.Name == sheetName);
            var worksheetPart = (WorksheetPart)(workbookPart.GetPartById(sheet.Id));
            var sheetData = worksheetPart.Worksheet.Elements<SheetData>().First();

            foreach (var row in sheetData.Elements<Row>())
            {
                foreach (var cell in row.Elements<Cell>())
                {
                    Console.Write("|" + GetCellValue(cell, workbookPart));
                }
                Console.Write("\n");
            }
        }
    }

    /// <summary>
    /// Got code from: https://msdn.Microsoft.com/en-us/library/office/hh298534.aspx
    /// </summary>
    /// <param name="cell"></param>
    /// <param name="workbookPart"></param>
    /// <returns></returns>
    private string GetCellValue(Cell cell, WorkbookPart workbookPart)
    {
        if (cell == null)
        {
            return null;
        }

        var value = cell.CellFormula != null
            ? cell.CellValue.InnerText 
            : cell.InnerText.Trim();

        // If the cell represents an integer number, you are done. 
        // For dates, this code returns the serialized value that 
        // represents the date. The code handles strings and 
        // Booleans individually. For shared strings, the code 
        // looks up the corresponding value in the shared string 
        // table. For Booleans, the code converts the value into 
        // the words TRUE or FALSE.
        if (cell.DataType == null)
        {
            return value;
        }
        switch (cell.DataType.Value)
        {
            case CellValues.SharedString:

                // For shared strings, look up the value in the
                // shared strings table.
                var stringTable =
                    workbookPart.GetPartsOfType<SharedStringTablePart>()
                        .FirstOrDefault();

                // If the shared string table is missing, something 
                // is wrong. Return the index that is in
                // the cell. Otherwise, look up the correct text in 
                // the table.
                if (stringTable != null)
                {
                    value =
                        stringTable.SharedStringTable
                            .ElementAt(int.Parse(value)).InnerText;
                }
                break;

            case CellValues.Boolean:
                switch (value)
                {
                    case "0":
                        value = "FALSE";
                        break;
                    default:
                        value = "TRUE";
                        break;
                }
                break;
        }
        return value;
    }
0
Jess