Optimale Möglichkeit zum Lesen einer Excel-Datei (.xls / .xlsx)

76

Ich weiß, dass es verschiedene Möglichkeiten gibt, eine Excel-Datei zu lesen:

  • Iterop
  • Oledb
  • Open Xml SDK

Kompatibilität ist keine Frage, da das Programm in einer kontrollierten Umgebung ausgeführt wird.

Meine Anforderung:
Lesen Sie eine Datei in a DataTable/ CUstom Entities (Ich weiß nicht, wie dynamische Eigenschaften / Felder für ein Objekt erstellt werden sollen [Spaltennamen variieren in einer Excel-Datei])

Verwenden Sie DataTable/Custom Entitiesdiese Option , um einige Vorgänge mithilfe der Daten auszuführen.

Aktualisieren Sie DataTablemit den Ergebnissen der Operationen

Schreiben Sie es zurück an excel file.

Welches wäre einfacher.

Wenn möglich, beraten Sie mich auch zu benutzerdefinierten Entitäten (dynamisches Hinzufügen von Eigenschaften / Feldern zu einem Objekt)

Ankesh
quelle
@AmiramKorach was abput schreiben zurück zu übertreffen ....
Ankesh
Ich benutze dafür einen kommerziellen Dritten. Dies wurde hier gestapelt stackoverflow.com/questions/1527790/…
Amiram Korach
Ich denke , dass eine der effizientesten Möglichkeiten , mit GemBox.Spreadsheet Bibliothek ist , die für die direkten Methoden haben den Export DataTablezu Blatt und Export Blatt zuDataTable .
Hazel Patton
Nur ein kleiner hilfreicher Rat, Excel-Dateien sind nur Zip-Dateien. Wenn Sie eine Excel-Datei extrahieren, bleiben Ihnen einige Ordner übrig. Die Zeichenfolgen für die Datei werden in "[Dateinamenordner] /xl/sharedStrings.xml" und die Arbeitsmappen in "[Dateinamenordner] /xl/workbook.xml" gespeichert. Theoretisch können Sie die Excel-Datei einfach programmgesteuert entpacken und Informationen aus der Datei extrahieren extrahierte Dateien.
Zach Pedigo

Antworten:

72

Schauen Sie sich Linq-to-Excel an . Es ist ziemlich ordentlich.

var book = new LinqToExcel.ExcelQueryFactory(@"File.xlsx");

var query =
    from row in book.Worksheet("Stock Entry")
    let item = new
    {
        Code = row["Code"].Cast<string>(),
        Supplier = row["Supplier"].Cast<string>(),
        Ref = row["Ref"].Cast<string>(),
    }
    where item.Supplier == "Walmart"
    select item;

Es ermöglicht auch einen stark typisierten Zeilenzugriff.

Rätselhaftigkeit
quelle
4
Beachten Sie, dass Linq-to-Excel eine Liste von Bibliotheken von Drittanbietern verwendet.
Fschricker
5
@fschricker - Nur zwei - "log4net" & "Remotion".
Rätselhaftigkeit
11
Und das Access Database Engine, das, obwohl Microsoft eine weitere Abhängigkeit darstellt.
Alan B
4
Obwohl nett ... ist dies aufgrund der "Access Database Engine" kein brauchbares Produktionsobjekt.
Gefangener NULL
8
Nicht um ein 'Troll' zu sein ... aber ... falls jemand darüber nachdenkt, dies zu benutzen. Der einzige Ort, an dem Sie es "wahrscheinlich" verwenden können, ist von Ihrem eigenen Desktop aus. Niemand wird Sie das "Access Database Engine" auf Client-Desktops oder Webservern installieren lassen ... und an vielen Orten (aus gutem Grund) können Sie solche Dinge nicht einmal lokal installieren. Auch hier liebe ich die Syntax und die Idee ... aber dies ist keine allgemein praktikable Lösung. Trotzdem ... sehr cool.
Gefangener NULL
27

Mit OLE Query ist es ganz einfach (zB sheetName ist Sheet1):

DataTable LoadWorksheetInDataTable(string fileName, string sheetName)
{           
    DataTable sheetData = new DataTable();
    using (OleDbConnection conn = this.returnConnection(fileName))
    {
       conn.Open();
       // retrieve the data using data adapter
       OleDbDataAdapter sheetAdapter = new OleDbDataAdapter("select * from [" + sheetName + "$]", conn);
       sheetAdapter.Fill(sheetData);
       conn.Close();
    }                        
    return sheetData;
}

private OleDbConnection returnConnection(string fileName)
{
    return new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + fileName + "; Jet OLEDB:Engine Type=5;Extended Properties=\"Excel 8.0;\"");
}

Für neuere Excel-Versionen:

return new OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + fileName + ";Extended Properties=Excel 12.0;");

Sie können Excel Data Reader auch als Open Source-Projekt in CodePlex verwenden. Es funktioniert sehr gut, um Daten aus Excel-Tabellen zu exportieren.

Der auf dem angegebenen Link angegebene Beispielcode:

FileStream stream = File.Open(filePath, FileMode.Open, FileAccess.Read);

//1. Reading from a binary Excel file ('97-2003 format; *.xls)
IExcelDataReader excelReader = ExcelReaderFactory.CreateBinaryReader(stream);
//...
//2. Reading from a OpenXml Excel file (2007 format; *.xlsx)
IExcelDataReader excelReader = ExcelReaderFactory.CreateOpenXmlReader(stream);
//...
//3. DataSet - The result of each spreadsheet will be created in the result.Tables
DataSet result = excelReader.AsDataSet();
//...
//4. DataSet - Create column names from first row
excelReader.IsFirstRowAsColumnNames = true;
DataSet result = excelReader.AsDataSet();

//5. Data Reader methods
while (excelReader.Read())
{
//excelReader.GetInt32(0);
}

//6. Free resources (IExcelDataReader is IDisposable)
excelReader.Close();

Referenz: Wie importiere ich mit Microsoft.Office.Interop.Excel aus Excel in ein DataSet?

Furqan Safdar
quelle
4
Wo ist der Code für this.returnConnection(fileName)?
Maslow
Dies funktioniert in .NET Core OleDbnicht mehr, da es nicht verfügbar ist (da es nicht plattformübergreifend ist).
CodeMonkey
ExcelDataReader hat für mich funktioniert, wird aber jetzt unter github.com/ExcelDataReader/ExcelDataReader
Wernsey
1
Muss für jede Option das Access-Datenbankmodul installiert sein?
Jamshaid Kamran
System.Data.OleDb ist jetzt für den Dotnet-Kern verfügbar. Nuget.org/packages/System.Data.OleDb
nedstark179
22

Mir ist klar, dass diese Frage vor fast 7 Jahren gestellt wurde, aber es ist immer noch ein Top-Google-Suchergebnis für bestimmte Keywords beim Importieren von Excel-Daten mit C #. Daher wollte ich eine Alternative anbieten, die auf einigen aktuellen technischen Entwicklungen basiert.

Das Importieren von Excel-Daten ist zu einer so häufigen Aufgabe geworden, dass ich den Prozess optimiert und die Methode in meinem Blog dokumentiert habe: Der beste Weg, um Excel-Dateien in c # zu lesen .

Ich verwende NPOI, weil es Excel-Dateien ohne installiertes Microsoft Office lesen / schreiben kann und weder COM + noch Interops verwendet. Das heißt, es kann in der Cloud funktionieren!

Die wahre Magie liegt jedoch in der Zusammenarbeit mit NPOI Mapper von Donny Tian, da ich die Excel-Spalten Eigenschaften in meinen C # -Klassen zuordnen kann, ohne Code schreiben zu müssen. Es ist wunderschön.

Hier ist die Grundidee:

Ich erstelle eine .net-Klasse, die den Excel-Spalten entspricht, die mich interessieren:

        class CustomExcelFormat
        {
            [Column("District")]
            public int District { get; set; }

            [Column("DM")]
            public string FullName { get; set; }

            [Column("Email Address")]
            public string EmailAddress { get; set; }

            [Column("Username")]
            public string Username { get; set; }

            public string FirstName
            {
                get
                {
                    return Username.Split('.')[0];
                }
            }

            public string LastName
            {
                get
                {
                    return Username.Split('.')[1];
                }
            }
        }

Beachten Sie, dass ich basierend auf dem Spaltennamen eine Zuordnung vornehmen kann, wenn ich möchte!

Wenn ich dann die Excel-Datei verarbeite, muss ich nur noch Folgendes tun:

        public void Execute(string localPath, int sheetIndex)
        {
            IWorkbook workbook;
            using (FileStream file = new FileStream(localPath, FileMode.Open, FileAccess.Read))
            {
                workbook = WorkbookFactory.Create(file);
            }

            var importer = new Mapper(workbook);
            var items = importer.Take<CustomExcelFormat>(sheetIndex);
            foreach(var item in items)
            {
                var row = item.Value;
                if (string.IsNullOrEmpty(row.EmailAddress))
                    continue;

                UpdateUser(row);
            }

            DataContext.SaveChanges();
        }

Zugegeben, mein Code ändert die Excel-Datei selbst nicht. Ich speichere stattdessen die Daten mit Entity Framework in einer Datenbank (deshalb sehen Sie in meinem Beispiel "UpdateUser" und "SaveChanges"). Es gibt jedoch bereits eine gute Diskussion über SO, wie eine Datei mit NPOI gespeichert / geändert werden kann .

Dan
quelle
1
Das funktioniert wie ein Zauber! Bisher einfachste Lösung. Beide sind als NuGet-Paket erhältlich.
Stefan
1
Hallo Dan, ich könnte die Excel-Dateiverarbeitung ohne Excel-Software oder oledb-Treiber auf dem Server nicht auflösen. Aber damit konnte ich erreichen. Auch gute Leistung. Danke vielmals.
Ramakrishnankt
1
Wie kann ich dies für generische Excel-Dateien verwenden, ohne vorher deren Spaltennamen zu kennen? Zum Beispiel möchte ich lieber ein Blatt in eine DataTable exportieren.
David Piao
David Pio - Verwenden Sie die neue dynamicFunktion. Ich denke, das ist es, wonach du suchst. mapper.Take<dynamic>(0).ToList();
Piotr Kula
1
Genial, hat wie ein Zauber funktioniert und jede Menge Zeit gespart. Vielen Dank!
Flatpick13
6

Versuchen Sie, diesen kostenlosen Weg zu https://freenetexcel.codeplex.com zu verwenden

 Workbook workbook = new Workbook();

 workbook.LoadFromFile(@"..\..\parts.xls",ExcelVersion.Version97to2003);
 //Initialize worksheet
 Worksheet sheet = workbook.Worksheets[0];

 DataTable dataTable = sheet.ExportDataTable();
Hark.Tenl
quelle
5

Wenn Sie es auf nur (Open Office XML-Format) * .xlsx-Dateien beschränken können, ist EPPLus wahrscheinlich die beliebteste Bibliothek .

Bonus ist, es gibt keine anderen Abhängigkeiten. Einfach mit nuget installieren:

Install-Package EPPlus
Davewasthere
quelle
0

Versuchen Sie, die Aspose.cells-Bibliothek zu verwenden (nicht kostenlos, aber die Testversion reicht zum Lesen aus). Sie ist ziemlich gut

Install-package Aspose.cells

Es gibt Beispielcode:

using Aspose.Cells;
using System;

namespace ExcelReader
{
    class Program
    {
        static void Main(string[] args)
        {
            // Replace path for your file
            readXLS(@"C:\MyExcelFile.xls"); // or "*.xlsx"
            Console.ReadKey();
        }

        public static void readXLS(string PathToMyExcel)
        {
            //Open your template file.
            Workbook wb = new Workbook(PathToMyExcel);

            //Get the first worksheet.
            Worksheet worksheet = wb.Worksheets[0];

            //Get cells
            Cells cells = worksheet.Cells;

            // Get row and column count
            int rowCount = cells.MaxDataRow;
            int columnCount = cells.MaxDataColumn;

            // Current cell value
            string strCell = "";

            Console.WriteLine(String.Format("rowCount={0}, columnCount={1}", rowCount, columnCount));

            for (int row = 0; row <= rowCount; row++) // Numeration starts from 0 to MaxDataRow
            {
                for (int column = 0; column <= columnCount; column++)  // Numeration starts from 0 to MaxDataColumn
                {
                    strCell = "";
                    strCell = Convert.ToString(cells[row, column].Value);
                    if (String.IsNullOrEmpty(strCell))
                    {
                        continue;
                    }
                    else
                    {
                        // Do your staff here
                        Console.WriteLine(strCell);
                    }
                }
            }
        }
    }
}
fr0ga
quelle
1
Es ist nicht kostenlos und hat Lizenzbeschränkungen, nachdem einige Analysen durchgeführt wurden (1K oder so, denke ich)
Mehmet Kurtipek
-1

Lesen Sie aus Excel, ändern Sie und schreiben Sie zurück

 /// <summary>
/// /Reads an excel file and converts it into dataset with each sheet as each table of the dataset
/// </summary>
/// <param name="filename"></param>
/// <param name="headers">If set to true the first row will be considered as headers</param>
/// <returns></returns>
public DataSet Import(string filename, bool headers = true)
{
    var _xl = new Excel.Application();
    var wb = _xl.Workbooks.Open(filename);
    var sheets = wb.Sheets;
    DataSet dataSet = null;
    if (sheets != null && sheets.Count != 0)
    {
        dataSet = new DataSet();
        foreach (var item in sheets)
        {
            var sheet = (Excel.Worksheet)item;
            DataTable dt = null;
            if (sheet != null)
            {
                dt = new DataTable();
                var ColumnCount = ((Excel.Range)sheet.UsedRange.Rows[1, Type.Missing]).Columns.Count;
                var rowCount = ((Excel.Range)sheet.UsedRange.Columns[1, Type.Missing]).Rows.Count;

                for (int j = 0; j < ColumnCount; j++)
                {
                    var cell = (Excel.Range)sheet.Cells[1, j + 1];
                    var column = new DataColumn(headers ? cell.Value : string.Empty);
                    dt.Columns.Add(column);
                }

                for (int i = 0; i < rowCount; i++)
                {
                    var r = dt.NewRow();
                    for (int j = 0; j < ColumnCount; j++)
                    {
                        var cell = (Excel.Range)sheet.Cells[i + 1 + (headers ? 1 : 0), j + 1];
                        r[j] = cell.Value;
                    }
                    dt.Rows.Add(r);
                }

            }
            dataSet.Tables.Add(dt);
        }
    }
    _xl.Quit();
    return dataSet;
}



 public string Export(DataTable dt, bool headers = false)
    {
        var wb = _xl.Workbooks.Add();
        var sheet = (Excel.Worksheet)wb.ActiveSheet;
        //process columns
        for (int i = 0; i < dt.Columns.Count; i++)
        {
            var col = dt.Columns[i];
            //added columns to the top of sheet
            var currentCell = (Excel.Range)sheet.Cells[1, i + 1];
            currentCell.Value = col.ToString();
            currentCell.Font.Bold = true;
            //process rows
            for (int j = 0; j < dt.Rows.Count; j++)
            {
                var row = dt.Rows[j];
                //added rows to sheet
                var cell = (Excel.Range)sheet.Cells[j + 1 + 1, i + 1];
                cell.Value = row[i];
            }
            currentCell.EntireColumn.AutoFit();
        }
        var fileName="{somepath/somefile.xlsx}";
        wb.SaveCopyAs(fileName);
        _xl.Quit();
        return fileName;
    }
Seinnin
quelle
Bitte antworten Sie mit einem Mindestarbeitscode!
Remo
Was ist Ihr Problem, damit es funktioniert?
Sein