Оптимальний спосіб читання файлу Excel (.xls / .xlsx)


77

Я знаю, що існують різні способи читання файлу Excel:

  • Iterop
  • Oledb
  • Open Xml SDK

Сумісність не є питанням, оскільки програма буде виконуватися в контрольованому середовищі.

Моя вимога:
зчитування файлу в a DataTable/ CUstom Entities (я не знаю, як зробити динамічні властивості / поля для об’єкта [імена стовпців будуть змінюватися у файлі Excel])

Використовуйте DataTable/Custom Entitiesдля виконання деяких операцій з використанням його даних.

Оновлення DataTableрезультатів операцій

Напишіть назад excel file.

Що було б простіше.

Також, якщо це можливо, дайте мені поради щодо користувацьких сутностей (динамічне додавання властивостей / полів до об'єкта)


@AmiramKorach те, що abput пише назад, щоб перевершити ....
Ankesh

Для цього я використовую комерційну третю сторону. Це запитували тут stackoverflow.com/questions/1527790/…
Amiram Korach

Я думаю, що одним з найбільш ефективних способів є використання бібліотеки GemBox.Spreadsheet, яка має прямі методи експорту DataTableв аркуш та експорту аркуша вDataTable .
Хейзел Паттон

Лише невелика корисна порада, файли Excel - це лише zip-файли. Витягнувши файл Excel, у вас залишиться кілька папок. Рядки для файлу зберігаються в "[filenamefolder] /xl/sharedStrings.xml", а книги - у "[filenamefolder] /xl/workbook.xml" Теоретично ви можете просто розпакувати файл excel програмним способом і витягти інформацію з витягнуті файли.
Зак Педіго,

Відповіді:


72

Погляньте на Linq-to-Excel . Це досить акуратно.

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;

Це також дозволяє отримати строко набраний рядок.


4
Зверніть увагу, що Linq-to-Excel використовує список сторонніх бібліотек.
fschricker

5
@fschricker - Лише два - "log4net" & "Remotion".
Enigmativity

11
І механізм бази даних Access, який, хоча Microsoft, є ще однією залежністю.
Алан Б

4
Хоча приємно ... це не життєздатний виробничий актив через "Access Database Engine".
В'язень НУЛЬ

8
Не бути «тролем» ... але ... на випадок, якщо хтось задумається про це. Єдиним місцем, де ви можете "скоріше" скористатися, є власний робочий стіл. Ніхто не збирається дозволяти вам встановлювати "Access Database Engine" на клієнтських робочих столах або веб-серверах ... і багато де (з поважних причин) навіть не дозволяють вам встановлювати подібні речі локально. Знову ж таки, я люблю синтаксис і мені подобається ідея ... але це не є життєздатним рішенням. Все-таки ... дуже класно.
В'язень ZERO

27

За допомогою OLE-запиту це досить просто (наприклад, sheetName - 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;\"");
}

Для нових версій Excel:

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

Ви також можете використовувати програму читання даних Excel з відкритим кодом на CodePlex. Це дуже добре працює для експорту даних з аркушів Excel.

Зразок коду, наведеного за вказаним посиланням:

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();

Довідково: Як імпортувати з Excel у набір даних за допомогою Microsoft.Office.Interop.Excel?


4
де код this.returnConnection(fileName)?
Маслоу

Це більше не працює в .NET Core, оскільки OleDbнедоступне (оскільки воно не є крос-платформним).
codeMonkey

ExcelDataReader працював у мене, але зараз він розміщений на github.com/ExcelDataReader/ExcelDataReader
Wernsey,

1
Чи кожна опція вимагатиме встановлення механізму баз даних Access?
Джамшаїд К.

System.Data.OleDb тепер доступний для dotnet
nedstark179

23

Я усвідомлюю, що це запитання було задано майже 7 років тому, але воно все ще є найкращим результатом пошуку Google за певними ключовими словами щодо імпорту даних Excel з C #, тому я хотів запропонувати альтернативу на основі деяких останніх технологічних розробок.

Імпорт даних Excel став настільки звичним завданням для моїх повсякденних обов'язків, що я впорядкував процес і задокументував метод у своєму блозі: найкращий спосіб читати файл Excel у c # .

Я використовую NPOI, оскільки він може читати / писати файли Excel без встановлення Microsoft Office і не використовує COM + або будь-які взаємодії. Це означає, що він може працювати в хмарі!

Але справжня магія виникає в поєднанні з NPOI Mapper від Donny Tian, оскільки це дозволяє мені зіставляти стовпці Excel із властивостями моїх класів C # без написання коду. Це красиво.

Ось основна ідея:

Я створюю клас .net, який відповідає / відображає стовпці Excel, які мене цікавлять:

        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];
                }
            }
        }

Зверніть увагу, це дозволяє мені робити карту на основі назви стовпця, якщо я хочу!

Тоді, коли я обробляю файл Excel, все, що мені потрібно зробити, це приблизно так:

        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();
        }

Тепер, правда, мій код не змінює сам файл Excel. Натомість я зберігаю дані у базі даних за допомогою Entity Framework (саме тому в моєму прикладі ви бачите «UpdateUser» та «SaveChanges»). Але на SO вже є хороша дискусія про те, як зберегти / змінити файл за допомогою NPOI .


1
Це працює як шарм! На сьогоднішній день найпростіше рішення. Обидва вони доступні як пакет NuGet.
Стефан

1
Привіт, Дене, я не зміг вирішити обробку файлів Excel без програмного забезпечення excel або драйверів oledb на сервері. Але використовуючи це, я зміг досягти. Також хороша продуктивність. Дуже дякую.
Рамакрішнанкт,

1
Як я можу використовувати це для загальних файлів Excel, не знаючи раніше їх назв стовпців? Наприклад, я б хотів експортувати аркуш у DataTable.
Девід Піао

Девід Піо - Використовуйте нову dynamicфункцію. Я думаю, це те, що ви шукаєте. mapper.Take<dynamic>(0).ToList();
Piotr Kula

1
Чудово, працював як шарм і економив багато часу. Дякую!
Flatpick13

6

Спробуйте скористатися цим безкоштовним способом, https://freenetexcel.codeplex.com

 Workbook workbook = new Workbook();

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

 DataTable dataTable = sheet.ExportDataTable();

5

Якщо ви можете обмежити його лише (формат XML у форматі Open Office) * .xlsx, то, мабуть, найпопулярнішою бібліотекою буде EPPLus .

Бонусом є те, що інших залежностей немає. Просто встановіть за допомогою nuget:

Install-Package EPPlus

0

Спробуйте скористатися бібліотекою Aspose.cells (не безкоштовно, але для ознайомлення достатньо пробної версії), це непогано

Install-package Aspose.cells

Є зразок коду:

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);
                    }
                }
            }
        }
    }
}

1
він не безкоштовний і має ліцензійні обмеження після певного розбору (
приблизно

-1

Читайте з Excel, модифікуйте та переписуйте

 /// <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;
    }
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.