Tworzenie pliku Excel w C# (Open XML SDK)

Pokażę teraz, jak skonstruować plik Excel w C# — bez instalowania samego Excela na serwerze. Użyjemy biblioteki Open XML SDK (DocumentFormat.OpenXml), oficjalnego pakietu Microsoftu do czytania i zapisu formatów Office (.xlsx, .docx, .pptx) na czystym XML-u, bez zależności od zainstalowanego Office.
To trzyczęściowa seria: tutaj tworzymy podstawowy skoroszyt z pojedynczą wartością, w części 2 dodajemy stylowanie komórek (czcionki, kolory, obramowania, szerokości kolumn), a w części 3 generujemy wykres słupkowy na podstawie danych w arkuszu.
Open XML SDK vs biblioteki wyższego poziomu
Zanim zaczniemy — warto wiedzieć, że Open XML SDK jest celowo niskopoziomowe. Odzwierciedla dokładną strukturę wewnętrzną pliku .xlsx (który jest w rzeczywistości archiwum ZIP z plikami XML w środku), więc nawet zapisanie jednej komórki wymaga kilku kroków: dokument → część skoroszytu → część arkusza → dane arkusza → wiersz → komórka. Biblioteki takie jak ClosedXML czy EPPlus owijają tę złożoność w znacznie prostsze API (worksheet.Cell("A1").Value = "test";). Open XML SDK ma jednak przewagę tam, gdzie liczy się wydajność przy generowaniu bardzo dużych plików albo brak zależności licencyjnych — EPPlus w wersjach komercyjnych wymaga płatnej licencji, Open XML SDK jest w pełni darmowe i oficjalnie wspierane przez Microsoft.
Krok po kroku
- Przechodzimy do Visual Studio i tworzymy nową aplikację konsolową C#.
- Dodajemy odniesienie do pakietu NuGet: DocumentFormat.OpenXml
- Dodajemy nową klasę i nazywamy ją np. Test
- Tworzymy publiczną metodę o nazwie CreateExcelDoc. W tej metodzie utworzymy i zapiszemy nasz plik Excel.
- Importujemy odpowiednie przestrzenie nazw.
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Spreadsheet;
namespace Pdf
{
public class Test
{
public void CreateExcelDoc(string fileName)
{
}
}
}6. Tworzymy nowy dokument arkusza kalkulacyjnego i przekazujemy nazwę pliku oraz typ dokumentu jako parametry.
using (SpreadsheetDocument document = SpreadsheetDocument.Create(fileName, SpreadsheetDocumentType.Workbook))
{ }7. SpreadsheetDocument musi mieć WorkbookPart i WorksheetPart. Dodamy następujący kod w bloku using.
using (SpreadsheetDocument document = SpreadsheetDocument.Create(fileName, SpreadsheetDocumentType.Workbook))
{
WorkbookPart workbookPart = document.AddWorkbookPart();
workbookPart.Workbook = new Workbook();
WorksheetPart worksheetPart = workbookPart.AddNewPart<WorksheetPart>();
worksheetPart.Worksheet = new Worksheet(new SheetData());
}8. Dołączamy arkusze do skoroszytu. Skoroszyt będzie zawierać jeden lub wiele arkuszy.
Sheets sheets = workbookPart.Workbook.AppendChild(new Sheets());9. Następnie dodajemy jeden lub wiele arkuszy.
Sheet sheet = new Sheet() { Id = workbookPart.GetIdOfPart(worksheetPart), SheetId = 1, Name = "Arkusz 1" };
sheets.Append(sheet);10. Na koniec zapis skoroszytu.
workbookPart.Workbook.Save();11. W metodzie Main klasy Program tworzymy obiekt naszej klasy Test i wywołujemy metodę CreateExcelDoc, przekazując ścieżkę do pliku.
static void Main(string[] args)
{
Test test = new Test();
test.CreateExcelDoc(@"C:\Excel\test.xlsx");
}12. Jeśli chcemy coś zapisać, dodajemy SheetData do arkusza. SheetData działa jak kontener, do którego trafiają wszystkie wiersze i kolumny.
SheetData sheetData = worksheetPart.Worksheet.AppendChild(new SheetData());13. Następnie dodajemy wiersz Row. Klasa Row reprezentuje wiersz w arkuszu kalkulacyjnym. Każdy wiersz może zawierać jedną lub więcej komórek Cell. Każda komórka ma CellValue, która zawiera rzeczywistą wartość, oraz DataType, który mówi Excelowi, jak tę wartość interpretować.
Row row = new Row();
Cell cell = new Cell() { CellValue = new CellValue("test"), DataType = CellValues.String };
row.Append(cell);
sheetData.AppendChild(row);
worksheetPart.Worksheet.Save();Pułapka: komórki liczbowe zapisane jako String
Częsty błąd początkujących z Open XML SDK: zapisanie liczby jako DataType = CellValues.String zamiast CellValues.Number. Plik otworzy się bez błędu, ale w Excelu taka “liczba” będzie wyrównana do lewej (jak tekst), nie zsumuje się w formule SUM(), i Excel nie pozwoli jej posortować numerycznie:
// ❌ Wygląda jak liczba, ale Excel traktuje ją jak tekst
var zlyTyp = new Cell() { CellValue = new CellValue("42"), DataType = CellValues.String };
// ✅ Poprawnie — Excel rozpozna to jako liczbę
var dobryTyp = new Cell() { CellValue = new CellValue(42), DataType = CellValues.Number };Ten sam mechanizm zobaczysz w części 3, gdzie wartości liczbowe dla wykresu muszą być poprawnie otypowane, żeby Excel w ogóle mógł je narysować.
Cały kod klasy Test
public class Test
{
public void CreateExcelDoc(string fileName)
{
using (SpreadsheetDocument document = SpreadsheetDocument.Create(fileName, SpreadsheetDocumentType.Workbook))
{
WorkbookPart workbookPart = document.AddWorkbookPart();
workbookPart.Workbook = new Workbook();
WorksheetPart worksheetPart = workbookPart.AddNewPart<WorksheetPart>();
worksheetPart.Worksheet = new Worksheet();
Sheets sheets = workbookPart.Workbook.AppendChild(new Sheets());
Sheet sheet = new Sheet() { Id = workbookPart.GetIdOfPart(worksheetPart), SheetId = 1, Name = "Arkusz 1" };
sheets.Append(sheet);
workbookPart.Workbook.Save();
SheetData sheetData = worksheetPart.Worksheet.AppendChild(new SheetData());
Row row = new Row();
Cell cell = new Cell() { CellValue = new CellValue("napis test "), DataType = CellValues.String };
row.Append(cell);
sheetData.AppendChild(row);
worksheetPart.Worksheet.Save();
}
}
}Uruchom projekt i sprawdź wygenerowany plik Excel. Cały kod źródłowy serii dostępny jest na GitHubie.
FAQ
Czy blok using wystarczy, żeby plik na pewno się zapisał?using gwarantuje wywołanie Dispose(), ale to jawne wywołania Save() na poszczególnych częściach (Workbook.Save(), Worksheet.Save()) faktycznie zapisują dane do wewnętrznego archiwum — pomiń jedno z nich, a odpowiadająca mu część pliku pozostanie pusta lub nieaktualna.
Czy mogę tym samym mechanizmem czytać istniejące pliki Excel, nie tylko je tworzyć?
Tak — SpreadsheetDocument.Open(fileName, isEditable: false) otwiera istniejący plik do odczytu tą samą biblioteką, choć nawigacja po już istniejącej strukturze XML bywa równie żmudna jak jej tworzenie.
🚀 Co dalej?
Zobacz to w praktyce na wideo i pobierz darmową roadmapę, żeby ułożyć naukę w spójną ścieżkę do pierwszej pracy.
- 🗺️ Pobierz darmową roadmapę Junior .NET Developer — 12 kroków od podstaw C# do pierwszej pracy: dev-hobby.pl
- 🎬 Subskrybuj kanał YouTube — nowe filmy co tydzień.
53 comments
Dodaj komentarz
Musisz się zalogować, aby móc dodać komentarz.
Zamień wiedzę w umiejętności
Pobierz darmową Roadmapę .NET i ułóż takie tematy jak ten w spójną ścieżkę do pierwszej pracy.
Pobieram roadmapę →
Cześć. Całkiem ciekawy artykuł. Mam jednak problem z decimalami. Jak można je dodać? DataType = CellValues.Number nie wystarczy i działa tylko na inty.
Some really choice posts on this site, bookmarked . Quintilla Denis Margaux
I have three of these already on my TBR. Great list. Almire Ruy Heeley
This paragraph is in fact a nice one it helps new net viewers, who are wishing for blogging. Elayne Shepard Derriey
Like!! I blog quite often and I genuinely thank you for your information. The article has truly peaked my interest. Belicia Gerard Mallin
I in addition to my buddies were studying the great helpful tips found on the blog while then came up with an awful feeling I never thanked the web site owner for those tips. My guys became for this reason excited to see all of them and now have pretty much been tapping into these things. Many thanks for genuinely indeed thoughtful as well as for making a decision on this kind of helpful resources millions of individuals are really needing to be aware of. My personal honest regret for not expressing appreciation to earlier. Malynda Timothee Ximenez
Its like you read my mind! You seem to know so much about this, like you wrote the book in it or something. I think that you can do with some pics to drive the message home a little bit, but other than that, this is magnificent blog. A great read. I will definitely be back. Tami Lyle Farrica
Appreciating the dedication you put into your blog and in depth information you provide. Wynny Reinald Theron
Having read this I believed it was rather informative. I appreciate you finding the time and energy to put this information together. I once again find myself spending a lot of time both reading and posting comments. But so what, it was still worth it! Mari Derron Chadburn
Wow, this post is pleasant, my younger sister is analyzing these kinds of things, therefore I am going to tell her.| Gwenore Morgun Penrose
This site is my inhalation, real fantastic layout and Perfect subject matter. Joellen Gonzales Cordula Elmira Rubin Lehmann
Hiya, I am really glad I have found this information. Today bloggers publish only about gossip and web stuff and this is really annoying. A good website with interesting content, this is what I need. Thanks for making this site, and I will be visiting again. Do you do newsletters by email? Allina Ralph Charline
I have read a few good stuff here. Definitely worth bookmarking for revisiting. I surprise how much effort you put to create such a magnificent informative site. Rosabel Augustus Clapper
I enjoy you because of all of your effort on this web site. My mother enjoys making time for investigation and it is simple to grasp why. We know all of the powerful medium you provide effective tips on the blog and as well foster contribution from other people on this concern then our favorite child has always been becoming educated a great deal. Take advantage of the rest of the year. Your carrying out a stunning job. Ashli Kermy Simdars
I have learn some good stuff here. Definitely worth bookmarking for revisiting. I surprise how so much attempt you set to make this type of fantastic informative website. Nathalia Roderic Naldo
I feel genuinely thrilled to have seen your current webpage and appearance forward to be able to so many more interesting times reading here. Cheers yet again for all typically the details. Beilul Hersh Jollenta
Thanks-a-mundo for the blog article. Really looking forward to read more. Engracia Elden Edouard Ivette Hillier Intosh
Great site. Plenty of helpful information here. I am sending it to several buddies ans additionally sharing in delicious. And naturally, thank you for your sweat! Cari Ryan Claudell
Touche. Outstanding arguments. Keep up the great spirit.| Anderea Odey Peggy
Hello, I enjoy readinhg all off you post. I wanted to write a little comment to support you. Morganica Timothy Ruperto
Major thanks for the blog. Much thanks again. Want more. Arlena Orrin Aubarta
I blog quite often and I truly appreciate your information. Your article has truly peaked my interest. I will book mark your site and keep checking for new information about once per week. I opted in for your Feed too. Renate Byram Braynard
Excellent, what a web site it is! This web site gives useful facts to us, keep it up. Yolanthe Rockey Compton
I like a very useful article, I like our page and follow it Vinnie Georgie Hungarian
Well I really enjoyed reading it. This tip provided by you is very constructive for accurate planning. Fernanda Lenard Oliy Ophelia Zolly Flinn
thanks
bardzo rzeczowy artykuł, dzieki
dzieki
Twoja metoda wyjaśniania wszystkiego w tym artykule jest naprawdę przyjemna, wszyscy mogą to łatwo zrozumieć. Wielkie dzięki.
dzieki
Po przejrzeniu kilku postów na blogu w Twojej witrynie, szczerze doceniam Twój sposób pisania bloga. Dokonałem rezerwacji i oznaczyłem to na mojej liście zakładek i wrócę w najbliższej przyszłości.
dzieki
Doskonały post. Absolutnie doceniam tę stronę. Pisz dalej! Eleanora Mal Mathis
dzieki
I’ve been browsing online greater than 3 hours as of late, but I by no means discovered any attention-grabbing article like yours.
It is lovely price enough for me. Personally, if all web owners and bloggers made excellent content as you probably did, the net can be
much more helpful than ever before.
thanks
Jesteś inspiracją dla wielu, którzy dopiero zaczynają swoją przygodę z dziedziną
Nice blog, favorite list add thanks.
Nice blog! Thanks you all star articles good story!
Nice bro thank you.
Nice bro thank you.
Doceniam twoje teksty i prawie wszystkie chłonę migiem, dziękuję za link z komentarza, on jest rankingowym dźwigiem.
Mam pytanie dotyczące [konkretnego fragmentu] artykułu. Czy możesz to wyjaśnić bardziej szczegółowo
Bardzo mi się podoba, jak zastosowano [omawianą technologię/metodologię] w praktyce. Przejrzyste wyjaśnienie z przykładami ułatwia zrozumienie.
bardzo przydatny wpis dobra robota
Bardzo ciekawe podejście do tematu. Zawsze warto patrzeć na to z różnych perspektyw
Jestem pod wrażeniem, jak potrafisz przekazywać informacje w sposób, który angażuje czytelnika od pierwszego zdania.
Dzięki za podkreślenie kluczowych aspektów [tematu]! To naprawdę pomogło mi zrozumieć istotę tego zagadnienia
Dzięki temu artykułowi zacząłem zastanawiać się nad [tematem] zupełnie inaczej. Naprawdę wartościowe spojrzenie
Bardzo doceniam, że zawsze dostarczasz źródła i dodatkowe materiały do pogłębienia wiedzy
Dzięki za dzielenie się swoją wiedzą. To naprawdę cenione
good job 🙂