c# Экспорт данных из DataGridView в Excel файл

Как выполнить экспорт данных из DataGridView в Excel файл?

В этой статье хочу показать на простом примере, как с помощью языка c# можно выполнить экспорт данных из DataGridView в Excel файл.

И так для начала создадим Windows Forms приложение на языке csharp, после чего добавим на форму два элемента управления: DataGridView (dgv) и кнопку с надписью: «Экспорт в Excel».

Windows Forms Application

Подготовка

И так для начала создадим метод CreateTable.

private DataTable CreateTable()
{
//создаём таблицу
DataTable dt = new DataTable("Friends");
//создаём три колонки
DataColumn colID = new DataColumn("ID", typeof(Int32));
DataColumn colName = new DataColumn("Name", typeof(String));
DataColumn colAge = new DataColumn("Age", typeof(Int32));
//добавляем колонки в таблицу
dt.Columns.Add(colID);
dt.Columns.Add(colName);
dt.Columns.Add(colAge);
DataRow row = null;
//создаём новую строку
row = dt.NewRow();
//заполняем строку значениями
row["ID"] = 1;
row["Name"] = "Vanya";
row["Age"] = 45;
//добавляем строку в таблицу
dt.Rows.Add(row);
//создаём ещё одну запись в таблице
row = dt.NewRow();
row["ID"] = 2;
row["Name"] = "Vasya";
row["Age"] = 35;
dt.Rows.Add(row);
return dt;
}

С помощью данного метода мы создадим таблицу с данными, которые затем, например, в событие Form.Load, загрузим в элемент управления DataGridView.

private void Form1_Load(object sender, EventArgs e)
{
dgv.DataSource = CreateTable();
}

Нажимаем F5 или Ctrl+F5 и получаем следующий результат.

control DataGridView

Экспорт в Excel

Первый этап закончен. Теперь переходим ко второму этапу, который так же начнётся с создания метода. И так, для начала создадим метод ExportToExcel. С помощью него, как думаю не трудно догадаться, мы собственно и будем выполнять экспорт данных в Excel файл.

private void ExportToExcel()
{
}

Для работы с Excel нам понадобиться добавить в проект сборку: Microsoft.Office.Interop.Excel.

Add references

подключение сборки

Чтобы каждый раз не обращаться к членам и типам данной сборки, используя полные имена, добавим следующую строку:

using Microsoft.Office.Interop.Excel;

Если сейчас Вы обратите своё внимание на написанный ранее код, то заметите, что в методе CreateTable имя класса DataTable почему-то стало подчеркнутым или выделенным красным цветом. Это произошло, потому что класс DataTable, присутствует как в пространстве имён Microsoft.Office.Interop.Excel так и в пространстве имён System.Data, в результате чего возник конфликт имён.

Чтобы разрешить возникший конфликт создадим псевдоним для пространства имён System.Data

//псевдоним
using SD = System.Data;

псевдоним

После чего в исходном коде перед именем класса DataTable укажем имя псевдонима.

private SD.DataTable CreateTable()
{
SD.DataTable dt = new SD.DataTable("Friends");
...
}

Конфликта больше нет и теперь можно работать дальше.

И так, чтобы выполнить экспорт данных в excel файл нам понадобиться для начала создать объект класса Application. Здесь так же возникает конфликт имен, поэтому в данном примере я создам ещё один псевдоним, но Вы можете просто указать полное имя:

using Excel = Microsoft.Office.Interop.Excel;

Затем внутри метода ExportToExcel создадим новый объект.

Excel.Application exApp = new Excel.Application();

Следующая строка используется для отладки, чтобы мы могли отслеживать результаты в ходе выполнения кода.

exApp.Visible = true; (данную строку можно не указывать)

Затем создадим одну новую рабочую книгу.

exApp.Workbooks.Add();

Excel рабочая книга

Созданная книга по умолчанию содержит три листа, поэтому добавлять их в данном примере не требуется. Поэтому сразу же получаем активный лист.

Worksheet workSheet = (Worksheet)exApp.ActiveSheet;

В первой строке листа мы поместим названия колонок.

workSheet.Cells[1, 1] = "ID";
workSheet.Cells[1, "B"] = "Name";
workSheet.Cells[1, 3] = "Age";

колонки

Первая цифра это номер строки, вторая ячейки. Вместо цифры Вы можете указывать и буквенное обозначение.

Экспортируем данные из DataGridView в Excel файл.

int rowExcel = 2; //начать со второй строки.
for (int i = 0; i < dgv.Rows.Count; i++)
{
//заполняем строку
 workSheet.Cells[rowExcel, "A"] = dgv.Rows[i].Cells["ID"].Value;
 workSheet.Cells[rowExcel, "B"] = dgv.Rows[i].Cells["Name"].Value;
workSheet.Cells[rowExcel, "C"] = dgv.Rows[i].Cells["Age"].Value;
++rowExcel;
}

Сохраняем результат в Excel файл.

string pathToXmlFile;
pathToXmlFile = Environment.CurrentDirectory + "\\" + "MyFile.xls";
workSheet.SaveAs(pathToXmlFile);

В данном примере файл будет создан в папке Debug текущего проекта.

Excel файл

И в конце завершаем работу с Microsoft Excel.

exApp.Quit();

Нам осталось выполнить последний шаг. В событие Button.Click поместим метод ExportToExcel.

private void button1_Click(object sender, EventArgs e)
{
ExportToExcel();
}

На этом экспорт завершен, окончательный результат можно увидеть на картинке ниже.

результат

Полный листинг:

private void ExportToExcel()
{
Excel.Application exApp = new Excel.Application();
exApp.Visible = true;
exApp.Workbooks.Add();
Worksheet workSheet = (Worksheet)exApp.ActiveSheet;
workSheet.Cells[1, 1] = "ID";
workSheet.Cells[1, 2] = "Name";
workSheet.Cells[1, 3] = "Age";
int rowExcel = 2;
for (int i = 0; i < dgv.Rows.Count; i++)
{
workSheet.Cells[rowExcel, "A"] = dgv.Rows[i].Cells["ID"].Value;
 workSheet.Cells[rowExcel, "B"] = dgv.Rows[i].Cells["Name"].Value;
workSheet.Cells[rowExcel, "C"] = dgv.Rows[i].Cells["Age"].Value;
++rowExcel;
}
workSheet.SaveAs("MyFile.xls");
exApp.Quit();
}

Если Вам нужно вывести данные не из DataGridView, а из DataTable то это, например можно сделать следующим образом:

//было
workSheet.Cells[rowExcel, "A"] = dgv.Rows[i].Cells["ID"].Value;
//стало
workSheet.Cells[rowExcel, "A"] = dt.Rows[i].Field<int>("ID");

На этом всё, если есть какие-то вопросы, то оставляйте их в комментариях.

Дополнение:

1. Свойство Visible влияет на быстродействие, поэтому перед выполнением цикла его лучше установить в значение false.

Excel.Application exApp = new Excel.Application();
exApp.Visible = false;
for()
{
}
exApp.Visible = true;

2. Большой объём данных можно быстро экспортировать, например, с помощью следующего способа:

//сохраняем данные из таблицы в xml файл
DataTable dt = new DataTable("Cars");
dt.WriteXml(pathToXmlFile);
//экспорт
Excel.Application exApp = new Excel.Application();
Excel.Workbook workbook = exApp.Workbooks.OpenXML(pathToXmlFile, Type.Missing, LoadOption.PreserveChanges);

В данном примере xml схема не используется (второй параметр), поэтому возможно появится сообщение: &#171;Указанный источник XML не ссылается на схему&#187; просто нажимаем кнопку &#171;OK&#187;.

Читайте также:

51 комментарий

  1. Александр says:

    как ни пытался ни получается на моем примере, возможна связь с вами чтобы показать свой пример?

  2. Что конкретно не получается?

  3. Александр says:

    у меня была база на access и там была кнопка экспорта, работала она отлично , сейчас делаю похожую прогу с подключением к mysql бд , и было много ошибок, благодаря вашему примеру я все сделал ошибки не выскальзывают , но если запросить данные в datagridview то экпорт не случается но страничку excel открывает, я уже все что можно испробовал&#8230;

  4. Код отвечающий за экспорт изменяли? Если да, то добавьте его в комментарий.

  5. Александр says:

    я уже сам разобрался), но у меня новый вопрос, мне нужны сделать поле поиска в таблице?

  6. Александр says:

    блин нет, не разобрался, в той форме где datagridview получает данные с таблицы которая имеет связь со всеми таблицами никак не хочет работать, остальные работают почти так как и нужно

  7. Не понял: &#171;сделать поле поиска в таблице?&#187;&#8230; поиск в dataGridView или БД?

  8. Александр says:

    да, блин может все поможешь с экспортом из бд? может быть беда в том, что таблица MyISAM? все остальные нормально экпортируются, а эта никак ваще не хочет&#8230;.

  9. &#171;никак ваще не хочет&#187; &#8212; что значит? Появляются какие-то ошибки или что происходит?
    Схема: БД -> DataTable -> DatagridView -> Excel файл?

  10. Александр says:

    у меня 5 разных форм с подключением к таблиц, 4 из них работают так как мне и нужно, 5-ая никак не хочет, хотя там код тот же самый и на других формах он работает а на этой ошибки.
    Необработанное исключение типа &#171;System.ArgumentException&#187; в mscorlib.dll
    Дополнительные сведения: Сигнатура типа метода не совместима с Interop.

  11. Нужно убрать блоки try catch, если они конечно есть и посмотреть, где во время выполнения программы возникает исключение. И уже разбираться дальше, может быть там null, может быть там преобразование типов нельзя выполнить, причин может быть масса.

    System.ArgumentException &#8212; &#171;исключение выбрасывается, если один из передаваемых методу аргументов является недопустимым&#187;.

    Как выглядит метод (сигнатура)? Что он должен принять (вход. параметры), и что он получает во время выполнения? Как выглядит строка, на которой происходит выброс исключения?

  12. Александр says:
    Microsoft.Office.Interop.Excel.Application ExcelApp = new Microsoft.Office.Interop.Excel.Application();
    ExcelApp.Application.Workbooks.Add(Type.Missing);
    ExcelApp.Columns.ColumnWidth = 20;
    ExcelApp.Cells[1, 2] = "№п";
    ExcelApp.Cells[1, 3] = "Пациент";
    ExcelApp.Cells[1, 4] = "Врач";
    ExcelApp.Cells[1, 5] = "Дата приема";
    ExcelApp.Cells[1, 6] = "Время";
    ExcelApp.Cells[1, 7] = "Услуга";
    ExcelApp.Cells[1, 8] = "стоимость";
    for (int j = 2; j <= dataGridView1.Rows.Count; j++)
    {
    for (int i = 2; i <= 7; i++)
    {
    ExcelApp.Cells[j, i] = dataGridView1.Rows[j - 2].Cells[i - 2].Value;
    }
    }
    ExcelApp.Visible = true;
  13. Александр says:

    try и catch есть только в подключении к бд. а программа ссылается на строку

    ExcelApp.Cells[j, i] = dataGridView1.Rows[j - 2].Cells[i - 2].Value;
  14. for (int i = 2; i < = 7; i++)

    — здесь точно 7, а не 8?

    Выбрасывает исключение "System.ArgumentException"?

  15. Александр says:

    да точно 7 должно быть, так как 7 столбцов и второй ответ тоже да, я не могу понять что не так то&#8230;

  16. 7 столбцов в DatagridView &#8212; это да, но почему тогда в цикле обход начинается с ячейки (2,2), в которую записывается значение первого столбца DataGridView? В таком случаи &#171;Стоимость&#187; уже не выводится, потому что последнее значение ячейки, которое будет взято из строки в dgv, будет равно (0, 5), а не (0,6).

    for (int j = 2; j < = dataGridView1.Rows.Count; j++)
    {
    for (int i=2; i
    

    Dgv:

    0 1 2 3 4 5 [6("Стоимость")] Count = 7

    Excel:

    2.1 (пропускаем) 2.2 (dgv.Rows[0].Cells[0]) 2.3(dgv[0][1]) Count=8
  17. Александр says:

    я знал это, и делал так в других формах у себя чтобы где то код пациента не высвечивался (он не нужен) в данном примере дело не в количестве значений, он бы без определенных столбцов экспортировал, я если честно ваще не понимаю уже что ему не нравиться&#8230;

  18. Александр says:

    вместо 7 поставил 8 и ничего не изменилось&#8230;

  19. У меня твой код экспорта работает без ошибок. Единственная проблема была только в том, что не заполнялась последняя ячейка в Excel файле.

  20. Александр says:

    я нашел в чем причина, ввел блоки try и catch перед строкой с ошибкой, в общем он не может переместить столбец с временем, столбец имеет тип time, теперь он у меня все строки перекидывает а столбец со временем пустые&#8230; можешь подсказать почему он время не перекидывает в excel&

  21. Как выглядит значение в колонке time (формат какой)?

  22. Александр says:

    00:00:00

  23. Александр says:

    можешь помочь? есть у меня поля для поисков, но они заменяют значения а не выбирают,

    string queryString = @"SELECT id_priema AS '№П', pacient.FIO AS 'Пациент', vrach.fio_vrach AS 'Врач',data_priema AS 'Дата', vremya AS 'Время', yslygi.opisanie AS 'Лечение', yslygi.stoimost AS  'Стоимость' FROM `priem` , `pacient`,`vrach` , `yslygi` WHERE fio_vrach LIKE '%" + textBox1.Text + "%';";
  24. Можно ToString после Value добавить.

    ExcelApp.Cells[2,2] = dgv.Rows[0].Cells[ячейка с временем].Value.ToString();

    &#171;можешь помочь? есть у меня поля для поисков, но они заменяют значения а не выбирают&#8230;&#187;

    Приведенный тобой sql запрос ничего не меняет, он делает только выборку. Проблема в чём-то другом.

  25. александр says:

    Это все на этой же форме, так жэ взял рабочий код, но на этой форме он не работает&#8230; Делал я вместо ввода фамилии конкретно поиск по id , но отображал 2 строки которые явно не те которые с этим id причем что работал при 1 и 3 на остальных никак

  26. Значит либо sql запрос составлен не верно, либо что-то другое.

  27. Александр says:

    Спасибо, со временем теперь все норм), жаль что я так и не успел разобрать с выборкой&#8230;

  28. Если посмотреть в диспетчере задач exel не выключается а если снова нажать в нем появляется новый excel

  29. exapp.quit(); написано

  30. Да, есть такая проблема.

    Можно закрыть все открытые процессы (Excel) после выхода из приложения, например так:

    Workbook wb = exApp.Workbooks.Add();
    excelBook.Close(0);
    excelApp.Quit();

    Либо можно завершить процесс не закрывая приложение:

    using System.Runtime.InteropServices; //добавить
    exApp.Quit();
    GC.Collect();
    GC.WaitForPendingFinalizers();
    Marshal.ReleaseComObject(workSheet);
    Marshal.ReleaseComObject(exApp);

    Сохраняет и завершает процесс.

  31. сергей says:

    Что делать, если в ссылке при добавлении нет Microsoft. Office. Interop.Excel&#8230;?

  32. сергей says:

    Уже скачал и разобрался

  33. Марат says:

    Здравствуйте, попытался ваш пример использовать , но у меня выделяет красным &#171;Worksheet&#187; вот в этом месте&#8230;

    Worksheet workSheet=(Worksheet)exApp.ActiveSheet;

    что мне делать?

  34. using Microsoft.Office.Interop.Excel;
    using Excel = Microsoft.Office.Interop.Excel;
    using SD = System.Data;

    Все добавлены?

  35. У меня программа с БД Microsoft Office Access 2007 клиент с запросами на C#.
    экспорт данных из DataGridView в Excel использовал ваш код .
    есть одно но таблица в Excel вся растянута и читать ни читаема
    под скажите как сделать желательно пример

  36. Николай says:

    На этой строчке вылетает workSheet.SaveAs(pathToXmlFile);
    Ошибка:
    Нет доступа к &#8216;MyFile.xls&#8217;.
    Как быть?

  37. Возможно файл уже открыт и в него происходит запись или, например файл не был создан, а в него пытаются что-то записать.
    Он существует по указанному пути?
    Если этот файл открыть, внести изменения (любые) и нажать кнопку сохранить, то всё нормально или возникают ошибки?

  38. Нуркасым says:

    у меня вопрос. Как можно изменить(открыть) уже созданный excel документ, после редактирования которого просто сохранить его и записать в БД. С открытием файла(перенос в DTGridView) разобрался, а дальше нет

  39. //открываем
    Excel.Application exApp = new Excel.Application();
    Excel.Workbook workbook = exApp.Workbooks.Open(@"C:имя_файла.xlsx");
    //выбираем активный лист
    Excel.Worksheet worksheet = workbook.ActiveSheet;
    //например, в ячейке первой строки было значение 2, а его нужно заменить на 5
    workSheet.Cells[1, "A"] = 5;
    //сохраняем изменения
    workbook.Save();
    //выход
    GC.Collect();
    GC.WaitForPendingFinalizers();
    Marshal.ReleaseComObject(workSheet);
    Marshal.ReleaseComObject(exApp);
  40. Виктория says:

    Во время заполнения таблицы Excel на строке

    workSheet.Cells[rowExcel, "A"] = dataGridView1.Rows[i].Cells["ID_факультатив"].Value;

    выдает ошибку: Не удается найти столбец с именем ID_факультатив. Имя параметра: columnName

    private void ExportToExcel()
    {
    Excel.Application exApp = new Excel.Application();
    exApp.Visible = true;
    exApp.Workbooks.Add();
    Worksheet workSheet = (Worksheet)exApp.ActiveSheet;
    workSheet.Cells[1, 1] = "ID_факультатив";
    workSheet.Cells[1, 2] = "Название";
    workSheet.Cells[1, 3] = "Класс";
    workSheet.Cells[1, 4] = "День";
    workSheet.Cells[1, 5] = "Урок";
    workSheet.Cells[1, 6] = "Учитель";
    int rowExcel = 2; //начать со второй строки.
    for (int i = 0; i <dataGridView1.Rows.Count; i++)
    {
    //заполняем строку
    workSheet.Cells[rowExcel, "A"] = dataGridView1.Rows[i].Cells["ID_факультатив"].Value;  //вот здесь
    workSheet.Cells[rowExcel, "B"] = dataGridView1.Rows[i].Cells["Название"].Value;
    workSheet.Cells[rowExcel, "C"] = dataGridView1.Rows[i].Cells["Класс"].Value;
    workSheet.Cells[rowExcel, "D"] = dataGridView1.Rows[i].Cells["День"].Value;
    workSheet.Cells[rowExcel, "E"] = dataGridView1.Rows[i].Cells["Урок"].Value;
    workSheet.Cells[rowExcel, "F"] = dataGridView1.Rows[i].Cells["Учитель"].Value;
    ++rowExcel;
  41. Виктория says:

    при этом шапку таблицы создает

  42. при этом шапку таблицы создает

    Ошибка не связана с Excel, поэтому шапка и выводится.

    выдает ошибку: Не удается найти столбец с именем ID_факультатив. Имя параметра: columnName

    Вместо &#171;ID_факультатив&#187; нужно указать свойство столбца ColumnName в DataGridView, а не HeaderText &#8212; текст заголовка колонки, который будет отображаться в DataGridView. Например:

    dataGridView1.Columns.Add("ID", "ID_Факультатив");
    workSheet.Cells[rowExcel, "A"] = dataGridView1.Rows[i].Cells["ID"].Value //OK;
    workSheet.Cells[rowExcel, "A"] = dataGridView1.Rows[i].Cells["ID_Факультатив"].Value //Exception;
  43. Виктория says:

    Спасибо большое за ответ!!!!!! Тем более такой быстрый)
    Уже разобралась)))))

  44. Александр says:

    Уважаемые товарищи!

    Если таблица 2х3, то заполнять ручками каждую ячейку вот так:

    //Visual Basic
    Public Sub export2excel(ByRef t As DataTable)
    Dim xls = New Excel.Application
    xls.Visible = False
    xls.Workbooks.Add()
    Dim Sheet As Excel.Worksheet = xls.Workbooks(1).ActiveSheet
    Dim row As Integer, col As Integer
    For row = 0 To t.Rows.Count - 1
    For col = 0 To t.Columns.Count - 1
    Sheet.Cells(row + 1, col + 1) = t(row)(col)
    Next
    Next
    xls.Visible = True
    End Sub

    &#8212; это приемлемо.

    А если у меня (в результате выполнения sql запроса к БД) получается таблица 20 колонок на 4000 строк, то это уже очень долго &#8212; минут 10 на Core i5. Может, есть какой-то способ передавать данные из DataTable в Worksheet оптом?

  45. В конце статьи есть один из способов.

  46. Александр says:

    Как то я проглядел этот способ, через xml.

    В итоге остановился на таком варианте:

    //Visual Basic
    Public Sub export2excel(ByRef t As DataTable, ByRef pgb As ProgressBar, ByVal b As Integer, ByVal e As Integer)
    If pgb IsNot Nothing Then
    pgb.Value = b
    End If
    Dim xls = New Excel.Application
    xls.Visible = False
    xls.Workbooks.Add()
    Dim ws As Excel.Worksheet = xls.Workbooks(1).ActiveSheet
    Dim arr(t.Rows.Count, t.Columns.Count) As Object
    Dim row As DataRow, r As Integer = 0, col As Integer
    Dim scale As Double = e - b
    scale = 0.8 * scale / t.Rows.Count
    For Each row In t.Rows
    If pgb IsNot Nothing Then
    pgb.Value = b + scale * r
    End If
    If r Mod 100 = 0 Then
    Update() ' это чтобы приложение не "подвисало" во время работы длинного цикла
    End If
    For col = 0 To t.Columns.Count - 1
    arr(r, col) = row(col)
    Next
    r = r + 1
    Next
    For col = 0 To t.Columns.Count - 1
    ws.Cells(1, col + 1) = t.Columns(col).Caption
    Next
    ws.Range("A1").Resize(1, t.Columns.Count).Font.Bold = True
    If pgb IsNot Nothing Then
    pgb.Value = b + (e - b) * 0.9
    End If
    ws.Range("A2").Resize(t.Rows.Count + 1, t.Columns.Count).Value = arr
    ws.Columns("A:ZZ").AutoFit()
    If pgb IsNot Nothing Then
    pgb.Value = e
    End If
    xls.Visible = True
    End Sub

    Тоже цикл, тоже перебирает ячейки по одной, но заполняет простой массив, а не worksheet.

    Второй момент, важно использовать for each row in &#8230;, а не for row = 0&#8230; &#8212; это тоже значительно ускоряет копирование. В итоге таблица 20х4000 передаётся за несколько секунд. Вполне wиндовая скорость.

    Прогрессбар можно не подавать, можно вместо него подать Nothing, тогда b и e (begin и end) &#8212; любые. Если используем ProgressBar, то подаём b>=pgb.Minimum e<=pgb.Maximum.

    В теле функции я pgb.Minimum и pgb.Maximum не трогаю намеренно, потому что подразумевается, что работа функции export2excel выполняет только часть процесса, например
    pgb.Minimum = 0
    pgb.Maximum = 100
    pgb.Value = 0
    получаем таблицу DataTable t &#8212; и пусть это будет 30%
    pgb.Value = 30
    export2excel(t, pgb, 30, 100) &#8212; &#039;экспорт в эксель займёт оставшиеся 30-70%

  47. Эльвира says:

    Не удалось получить фабрику класса COM для компонента с CLSID {00024500-0000-0000-C000-000000000046} из-за следующей ошибки: 80040154 Класс не зарегистрирован (Исключение из HRESULT: 0x80040154 (REGDB_E_CLASSNOTREG)).
    Ругается на первой же строчке

  48. Эльвира says:

    Подскажите пожалуйста, можно ли не создавать новый файл, а записывать данные уже в заранее подготовленный шаблон. Т.е. у меня в exel есть формулы и мне только нужно, чтобы программа обновляла поля, загруженные из DataGridView.

  49. Эльвира says:

    Извините, все проблемы решила

  50. Подскажите пожалуйста, можно ли не создавать новый файл, а записывать данные уже в заранее подготовленный шаблон

    Можно &#8212; это ведь обычный файл.

Leave a Reply

Ваш e-mail не будет опубликован. Обязательные поля помечены *

*