Odczytywanie plików Excel z C #


233

Czy istnieje darmowa lub otwarta biblioteka do odczytu plików Excel (.xls) bezpośrednio z programu C #?

Nie musi to być zbyt wymyślne, wystarczy wybrać arkusz i odczytać dane jako ciągi. Do tej pory korzystałem z funkcji eksportowania do Excela tekstu w formacie Unicode i analizowałem wynikowy (rozdzielany tabulatorami) plik, ale chciałbym wyeliminować krok ręczny.

Odpowiedzi:


153
var fileName = string.Format("{0}\\fileNameHere", Directory.GetCurrentDirectory());
var connectionString = string.Format("Provider=Microsoft.Jet.OLEDB.4.0; data source={0}; Extended Properties=Excel 8.0;", fileName);

var adapter = new OleDbDataAdapter("SELECT * FROM [workSheetNameHere$]", connectionString);
var ds = new DataSet();

adapter.Fill(ds, "anyNameHere");

DataTable data = ds.Tables["anyNameHere"];

Tego zwykle używam. Jest trochę inaczej, ponieważ zwykle edytuję tabele AsEnumerable ():

var data = ds.Tables["anyNameHere"].AsEnumerable();

ponieważ pozwala mi to używać LINQ do wyszukiwania i budowania struktur z pól.

var query = data.Where(x => x.Field<string>("phoneNumber") != string.Empty).Select(x =>
                new MyContact
                    {
                        firstName= x.Field<string>("First Name"),
                        lastName = x.Field<string>("Last Name"),
                        phoneNumber =x.Field<string>("Phone Number"),
                    });

Jeśli wydaje się, że Select w tym podejściu próbuje odgadnąć typ danych kolumny i wymusić na tym odgadniętym typie danych. Na przykład, jeśli masz kolumnę z przeważnie podwójnymi wartościami, nie spodoba ci się przekazanie x.Field <ciąg>, ale oczekuje x.Field <podwójny>. Czy to prawda?
Kevin Le - Khnle

1
Właśnie sprawdziłem to na MSDN. Wygląda na to, że <T> jest po prostu używany do próby rzutowania zawartości w kolumnie na typ. W tym przykładzie i po prostu rzutowanie danych w kolumnach na ciągi. Jeśli chcesz podwójnego, musisz wywołać double.Parse (x.Field <ciąg> („Koszt”) lub coś w tym rodzaju. Pole jest metodą rozszerzenia dla DataRow i wygląda na to, że nie ma wersji ogólnych.
Robin Robinson

Czy dodanie zapytania double.Parse do zapytania Linq znacznie go spowalnia?
Typ anonimowy

23
Pamiętaj, że jeśli czytasz xlsx, zamiast tego musisz użyć tego ciągu połączenia:string.Format("Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0}; Extended Properties=Excel 12.0;", fileName)
Andreas Grech

7
Niestety sterownik Jet.OLEDB nie jest kompatybilny z 64-bitami; musisz przełączyć się na docelowy procesor x86 zamiast na dowolny procesor (jeśli nadal chcesz korzystać z tej metody). Alternatywnie zainstaluj 64-bitowy sterownik ACE i zmień parametry Conn, aby używać tego sterownika (jak wskazał Andreas) - microsoft.com/en-us/download/…
Duncan

83

Jeśli są to tylko proste dane zawarte w pliku Excel, możesz je odczytać przez ADO.NET. Zobacz parametry połączenia wymienione tutaj:

http://www.connectionstrings.com/?carrier=excel2007 lub http://www.connectionstrings.com/?carrier=excel

-Ryan

Aktualizacja: możesz po prostu przeczytać arkusz roboczy za pomocą czegoś takiego select * from [Sheet1$]


1
Ta droga jest zdecydowanie najszybsza.
StingyJack

17
Oczywiście, że to nieprawda, Skąpy. Musisz przeszukać wszystkie dane i napisać kiepski kod DB (ręcznie twórz modele, mapuj kolumny na właściwości, yadda yadda). Najszybszym sposobem jest pozwolenie, aby jakiś inny biedny SOB zrobił to za ciebie . Dlatego ludzie używają frameworków zamiast pisać wszystko od podstaw.

12
Bezwartościowa metoda! Podczas czytania obcina kolumny tekstowe do 255 znaków. Strzec się! Zobacz: stackoverflow.com/questions/1519288/... Silnik ACE robi to samo!
Triynko

5
Należy pamiętać, że używanie ADO.NET do odczytu danych z exela wymaga zainstalowanego programu Microsoft Access lub Microsoft Access Database Engine Redistributable.
zihotki

3
Sterownik będzie również odgadywał typy kolumn na podstawie pierwszych kilku wierszy. Jeśli masz kolumnę z czymś, co wygląda jak liczby całkowite w pierwszych wierszach, napotkasz błąd, gdy uderzysz liczbę inną niż całkowita (np. Liczba zmiennoprzecinkowa, ciąg)
Brian Low

27

Podejście ADO.NET jest szybkie i łatwe, ale ma kilka dziwactw, o których powinieneś wiedzieć, szczególnie jeśli chodzi o sposób obsługi typów danych.

Ten doskonały artykuł pomoże Ci uniknąć niektórych typowych pułapek: http://blog.lab49.com/archives/196


Odpowiedziałeś na moje pytanie (w formie komentarza powyżej).
Kevin Le - Khnle

22

Oto, czego użyłem w programie Excel 2003:

Dictionary<string, string> props = new Dictionary<string, string>();
props["Provider"] = "Microsoft.Jet.OLEDB.4.0";
props["Data Source"] = repFile;
props["Extended Properties"] = "Excel 8.0";

StringBuilder sb = new StringBuilder();
foreach (KeyValuePair<string, string> prop in props)
{
    sb.Append(prop.Key);
    sb.Append('=');
    sb.Append(prop.Value);
    sb.Append(';');
}
string properties = sb.ToString();

using (OleDbConnection conn = new OleDbConnection(properties))
{
    conn.Open();
    DataSet ds = new DataSet();
    string columns = String.Join(",", columnNames.ToArray());
    using (OleDbDataAdapter da = new OleDbDataAdapter(
        "SELECT " + columns + " FROM [" + worksheet + "$]", conn))
    {
        DataTable dt = new DataTable(tableName);
        da.Fill(dt);
        ds.Tables.Add(dt);
    }
}

2
arkusz nie jest zdefiniowany ... wydaje mi się trochę dziwny po jasnym zdefiniowaniu wszystkiego innego.
Jeremy Holovacs,

21

Co z programem Excel Data Reader?

http://exceldatareader.codeplex.com/

Użyłem w tym gniewu, w środowisku produkcyjnym, do pobierania dużych ilości danych z różnych plików Excel do SQL Server Compact. Działa bardzo dobrze i jest dość solidny.


2
Będę drugim czytnikiem danych Excel; doprowadziło to również do niezwykle użytecznej biblioteki Excel Data Driven Tests, która wykorzystuje atrybut TestCaseSource NUnita 2.5 do uczynienia testów opartych na danych za pomocą arkuszy kalkulacyjnych Excel niezwykle śmiesznie. Uważaj tylko, że Resharper nie obsługuje jeszcze TestCaseSource, więc musisz użyć programu uruchamiającego NUnit.
David Keaveny,

Niestety z biblioteką, z którą właśnie się spotkaliśmy, są pewne problemy. Po pierwsze, pojawiły się pola walutowe jako daty. Po drugie następuje awaria, jeśli skoroszyt zawiera puste arkusze. Tak więc, chociaż integracja była bardzo łatwa, teraz ponownie oceniamy, czy nadal korzystać z tej biblioteki. Wydaje się, że nie jest aktywnie rozwijany.
Ian1971

Zakłada również obecność niektórych opcjonalnych elementów w pliku xlsx, które powodują, że nie można odczytać danych, jeśli są one nieobecne.
RichieHindle

Mamy problemy z plikami Excel pochodzącymi z SQL Server Reporting Services. Po prostu nie działają, chyba że je otworzysz i uratujesz (nawet bez edycji). @RichieHindle: o jakich elementach opcjonalnych mówisz (mam nadzieję, że to może mi pomóc z moimi plikami SSRS Excel)?
Peter

@Peter: Myślę, że był to brakujący <dimension>element, <worksheet>który sprawiał mi kłopoty.
RichieHindle

16

Oto kod, który napisałem w C # przy użyciu .NET 1.1 kilka lat temu. Nie jestem pewien, czy byłoby to dokładnie to, czego potrzebujesz (i może nie być moim najlepszym kodem :)).

using System;
using System.Data;
using System.Data.OleDb;

namespace ExportExcelToAccess
{
    /// <summary>
    /// Summary description for ExcelHelper.
    /// </summary>
    public sealed class ExcelHelper
    {
        private const string CONNECTION_STRING = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=<FILENAME>;Extended Properties=\"Excel 8.0;HDR=Yes;\";";

        public static DataTable GetDataTableFromExcelFile(string fullFileName, ref string sheetName)
        {
            OleDbConnection objConnection = new OleDbConnection();
            objConnection = new OleDbConnection(CONNECTION_STRING.Replace("<FILENAME>", fullFileName));
            DataSet dsImport = new DataSet();

            try
            {
                objConnection.Open();

                DataTable dtSchema = objConnection.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, null);

                if( (null == dtSchema) || ( dtSchema.Rows.Count <= 0 ) )
                {
                    //raise exception if needed
                }

                if( (null != sheetName) && (0 != sheetName.Length))
                {
                    if( !CheckIfSheetNameExists(sheetName, dtSchema) )
                    {
                        //raise exception if needed
                    }
                }
                else
                {
                    //Reading the first sheet name from the Excel file.
                    sheetName = dtSchema.Rows[0]["TABLE_NAME"].ToString();
                }

                new OleDbDataAdapter("SELECT * FROM [" + sheetName + "]", objConnection ).Fill(dsImport);
            }
            catch (Exception)
            {
                //raise exception if needed
            }
            finally
            {
                // Clean up.
                if(objConnection != null)
                {
                    objConnection.Close();
                    objConnection.Dispose();
                }
            }


            return dsImport.Tables[0];
            #region Commented code for importing data from CSV file.
            //              string strConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;" +"Data Source=" + System.IO.Path.GetDirectoryName(fullFileName) +";" +"Extended Properties=\"Text;HDR=YES;FMT=Delimited\"";
            //
            //              System.Data.OleDb.OleDbConnection conText = new System.Data.OleDb.OleDbConnection(strConnectionString);
            //              new System.Data.OleDb.OleDbDataAdapter("SELECT * FROM " + System.IO.Path.GetFileName(fullFileName).Replace(".", "#"), conText).Fill(dsImport);
            //              return dsImport.Tables[0];

            #endregion
        }

        /// <summary>
        /// This method checks if the user entered sheetName exists in the Schema Table
        /// </summary>
        /// <param name="sheetName">Sheet name to be verified</param>
        /// <param name="dtSchema">schema table </param>
        private static bool CheckIfSheetNameExists(string sheetName, DataTable dtSchema)
        {
            foreach(DataRow dataRow in dtSchema.Rows)
            {
                if( sheetName == dataRow["TABLE_NAME"].ToString() )
                {
                    return true;
                }   
            }
            return false;
        }
    }
}

Nie mogę zgodzić się na więcej Cheriana. Ten kod ma wiele lat ... zanim nawet byłem biegły w
Resharper

2
Kod jest brzydki, ale pokazuje, jak uzyskać nazwy arkuszy, świetnie!
Sam



8

Dużo czytałem z plików Excela w C # jakiś czas temu i zastosowaliśmy dwa podejścia:

  • Interfejs API COM, w którym uzyskujesz bezpośredni dostęp do obiektów Excela i manipulujesz nimi za pomocą metod i właściwości
  • Sterownik ODBC, który pozwala korzystać z Excela jak z bazy danych.

To drugie podejście było wiele szybsze: czytanie dużego stołu z 20 kolumnami i 200 wierszami zajęłoby 30 sekund przez COM i pół sekundy przez ODBC. Dlatego zalecałbym podejście do bazy danych, jeśli potrzebujesz tylko danych.

Twoje zdrowie,

Carl



6

Chcę pokazać prostą metodę odczytu pliku xls / xlsx w .NET. Mam nadzieję, że poniższe informacje będą dla Ciebie pomocne.

 prywatny DataTable ReadExcelToTable (ścieżka ciągu)    
 {

     //Ciąg połączenia

     string connstring = "Provider = Microsoft.ACE.OLEDB.12.0; Źródło danych =" + ścieżka + "; Rozszerzone właściwości = 'Excel 8.0; HDR = NIE; IMEX = 1';";  
     //to samo imię 
     // string connstring = Provider = Microsoft.JET.OLEDB.4.0; Źródło danych = „+ ścieżka + //”; Rozszerzone właściwości = „Excel 8.0; HDR = NIE; IMEX = 1”; ”; 

     using (OleDbConnection conn = new OleDbConnection (connstring))
     {
        conn.Open ();
        // Uzyskaj nazwę wszystkich arkuszy
        DataTable sheetName = conn.GetOleDbSchemaTable (OleDbSchemaGuid.Tables, nowy obiekt [] {null, null, null, "Table"});  

        // Uzyskaj nazwę pierwszego arkusza
        string firstSheetName = sheetName.Rows [0] [2] .ToString (); 

        // Ciąg zapytania 
        string sql = string.Format ("SELECT * FROM [{0}]", firstSheetName); 
        OleDbDataAdapter ada = nowy OleDbDataAdapter (sql, connstring);
        DataSet set = new DataSet ();
        ada.Fill (zestaw);
        return set.Tables [0];   
   }
 }

Kod pochodzi z artykułu: http://www.c-sharpcorner.com/uploadfile/d2dcfc/read-excel-file-with-net/ . Możesz uzyskać z niego więcej szczegółów.


2
Było to pomocne, szczególnie w części dotyczącej czytania nazw arkuszy.
martinstoeckli

4

Nie za darmo, ale z najnowszym pakietem Office jest bardzo ładna automatyzacja .Net API. (interfejs API był przez długi czas, ale był nieprzyjemny COM) Możesz zrobić wszystko, co chcesz / potrzebujesz w kodzie, podczas gdy aplikacja Office pozostaje ukrytym procesem w tle.


3
@ Anonimowy typ Przeczytałem pytanie i oferowałem pomocną alternatywę dla pożądanej implementacji OSS ... ponieważ, cóż, byłem prawie pewien, że nic nie jest dostępne. Sądząc po zaakceptowanej odpowiedzi, wymóg posiadania pakietu Office nie stanowi problemu.
Xanadont,

3

Wybacz mi, jeśli jestem tu poza bazą, ale czy nie po to są Office PIA ?


5
Tak, ale wymagałoby to utworzenia instancji Excel.Application, załadowania pliku xls itp. Jeśli wymaganiem jest jedynie odczyt niektórych danych z pliku, o wiele łatwiej i znacznie lżejsze jest użycie jednej z opisanych metod ADO.NET w innych odpowiedziach.
Adam Ralph

Zbyt wolno, używając Office PIA jako podstawy, wszystko inne jest szybsze - nawet po prostu używając tablicy Object przekazanej z właściwości .Value2. Który nadal korzysta z PIA.
Anonimowy typ

3

Ostatnio, częściowo po to, aby poprawić się w LINQ .... Korzystam z API automatyzacji Excela, aby zapisać plik jako arkusz kalkulacyjny XML, a następnie przetworzyć ten plik za pomocą LINQ to XML.


Podejrzewam, że możesz chronić go przed Excelem, ale nie przed człowiekiem z kompilatorem ... jak wszystko ... to tylko bajty.
kenny

@gsvirdi, opublikuj osobne pytanie dotyczące bezpieczeństwa plików Excela, to pytanie dotyczy wydajności.
Anonimowy typ


3

SmartXLS to kolejny składnik arkusza kalkulacyjnego programu Excel, który obsługuje większość funkcji wykresów programu Excel, silników formuł i może odczytywać / zapisywać format openxml programu excel2007.



2

Polecam bibliotekę FileHelpers, która jest darmową i łatwą w użyciu biblioteką .NET do importowania / eksportowania danych z EXCEL, ustalonych długości lub rozdzielonych rekordów w plikach, ciągach lub strumieniach i więcej.

Sekcja dokumentacji łącza danych Excel http://filehelpers.sourceforge.net/example_exceldatalink.html


1
Nie zawiodę cię, ale ostatnio zacząłem używać FileHelpers i byłem zszokowany tym, jak ... to gówno jest. Na przykład jedynym sposobem mapowania kolumn w pliku csv do właściwości ... przepraszam, FIELDS, modelu jest utworzenie pól w kolejności kolumn . Nie wiem o tobie, ale nie polegałbym na dziwactwie kompilatora, jeśli chodzi o jedną z najważniejszych kwestii projektowych mojego frameworka.


2

SpreadsheetGear jest niesamowity. Tak, to wydatek, ale w porównaniu z kręceniem się z innymi rozwiązaniami, jest wart kosztów. Jest szybki, niezawodny, bardzo wszechstronny i muszę powiedzieć, że po korzystaniu z tego produktu w pracy na pełnym etacie przez ponad półtora roku ich obsługa klienta jest fantastyczna!


Trudno uzasadnić, gdy istnieje tak wiele prostych i skutecznych sposobów (za darmo) czytania i pisania w Excelu.
Anonimowy typ

2

Zastosowane przez nas rozwiązanie wymagało:

  • Zezwalaj na odczyt / zapis plików wyprodukowanych w Excelu
  • Bądź szybki w działaniu (nie tak jak przy użyciu COM)
  • Bądź niezależny od MS Office (musiał być użyteczny bez klientów z zainstalowanym MS Office)
  • Bądź darmowy lub open source (ale aktywnie rozwijany)

Istnieje kilka możliwości, ale okazało się, że NPoi (port .NET od dawna istniejącego projektu open source Poi w Javie ) jest najlepszy: http://npoi.codeplex.com/

Umożliwia także pracę z formatami plików doc i ppt


2

Jeśli to tylko dane tabelaryczne. Poleciłbym pomocników do plików Marcos Melli, które można pobrać tutaj .



1

możesz napisać arkusz kalkulacyjny programu Excel, który ładuje dany arkusz kalkulacyjny programu Excel i zapisuje go jako plik csv (zamiast robić to ręcznie).

to możesz zautomatyzować to od c #.

a gdy już znajdzie się w csv, program c # może tego dokonać.

(jeśli ktoś poprosi cię o programowanie w programie Excel, najlepiej udawać, że nie wiesz jak)

(edytuj: ah tak, rob i Ryan mają rację)




1

Pakiet Excel jest komponentem typu open source (GPL) do odczytu / zapisu plików Excel 2007. Użyłem go w małym projekcie, a interfejs API jest prosty. Działa tylko z XLSX (Excel 200 i), nie z XLS.

Kod źródłowy również wydaje się dobrze zorganizowany i łatwy w obsłudze (jeśli musisz rozszerzyć funkcjonalność lub naprawić drobne problemy, tak jak ja).

Najpierw wypróbowałem podejście ADO.Net (ciąg połączenia Excela), ale było obrzydliwe włamania - na przykład, jeśli drugi wiersz zawiera liczbę, zwróci wartości int dla wszystkich pól w kolumnie poniżej i po cichu upuści wszelkie dane to nie pasuje.


1

Używamy ClosedXML w dość dużych systemach.

  • Wolny
  • Łatwe do zainstalowania
  • Proste kodowanie
  • Bardzo elastyczne wsparcie
  • Zespół programistów jest wyjątkowo otwarty na nowe sugestie. Często nowe funkcje i poprawki błędów są wdrażane w ciągu tego samego tygodnia

1

Take.ioArkusz kalkulacyjny wykona tę pracę za Ciebie i bez żadnych opłat. Spójrz na to .


To naprawdę świetna mała biblioteka. Po prostu konwertuje wszystko na Listy list ciągów, co jest w porządku dla rodzaju pracy, do której potrzebowałem.
Drewmate,

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.