Экспорт Excel с помощью Npoi

Я ищу, чтобы экспортировать лист Excel, используя библиотеку NPOI. Есть ли способ вставить данные в лист без потери формата данных?

Ранее я использовал библиотеку электронных таблиц Gembox. Это хорошо сработало для меня. Код для этого выглядит так:

    public void ExportTest(DataSet ds)
    {

        SpreadsheetInfo.SetLicense("FREE-LIMITED-KEY");
        ExcelFile ef = new ExcelFile();
        var filename = DateTime.Now.ToString("yyyyMMdd") + "BSI_MEMBERAmendment" + ".xls";
        foreach (DataTable dt in ds.Tables)
        {
            ExcelWorksheet ws = ef.Worksheets.Add(dt.TableName);
            ws.InsertDataTable(dt,
           new InsertDataTableOptions(0, 0)
           {
               ColumnHeaders = true,
               StartRow = 0,

           });
        }

        ef.Save(this.Response, filename);

Мне пришлось прекратить использовать библиотеку Gembox, потому что мне нужно создавать файлы Excel, содержащие более 5 листов. Gembox, к сожалению, не позволяет этого на бесплатной платформе. Поэтому я перешел на NPOI.

Теперь, когда я использую библиотеку NPOI, я изменил свой код на:

  public void WriteExcelWithNPOI(String extension, DataSet dataSet)
    {


        HSSFWorkbook workbook = new HSSFWorkbook(); ;

       if (extension == "xls")
        {
            workbook = new HSSFWorkbook();
        }
        else
        {
            throw new Exception("This format is not supported");
        }

        foreach (DataTable dt in dataSet.Tables)
        {
            var sheet1 = workbook.CreateSheet(dt.TableName);
            // How can i insert the data's from dataTable in this sheet
        }

        using (var exportData = new MemoryStream())
        {
            Response.Clear();
            workbook.Write(exportData);
            if (extension == "xls") 
            {
                Response.ContentType = "application/vnd.ms-excel";
                Response.AddHeader("Content-Disposition", string.Format("attachment;filename={0}", "tpms_dict.xls"));
                Response.BinaryWrite(exportData.GetBuffer());
            }
            Response.End();
        }
    }

Проблема, с которой я сталкиваюсь при использовании библиотеки NPOI, заключается в том, что все ячейки в экспортированном файле Excel отформатированы как текст. Я хотел бы сохранить формат, который используется в таблице данных. Ищу помощь. Заранее спасибо!!!

2 ответа

Чтобы вставить данные из таблицы данных, вы могли бы использовать этот код вместо комментария "// Как мне вставить данные из таблицы данных в этот лист".

// 1. make a header row
IRow row1 = sheet1.CreateRow(0);

for (int j = 0; j < dt.Columns.Count; j++)
{
    ICell cell = row1.CreateCell(j);
    string columnName = dt.Columns[j].ToString();
    cell.SetCellValue(columnName);
}

// 2. loop through data
for (int i = 0; i < dt.Rows.Count; i++)
{
    IRow row = sheet1.CreateRow(i + 1);
    for (int j = 0; j < dt.Columns.Count; j++)
    {
        ICell cell = row.CreateCell(j);
        string columnName = dt.Columns[j].ToString();
        cell.SetCellValue(dt.Rows[i][columnName].ToString());
    }
}
// 3. Auto size columns
for (int i = 0; i < 5; i++)
{
    for (int j = 0; j < row1.LastCellNum; j++)
    {
        sheet1.AutoSizeColumn(j);
    }
}

Для типов данных вы можете использовать функцию cell.SetCellType(CellType.[TYPE HERE]);. Тип, введенный в функциюSetCellType должен соответствовать типу данных в cell.SetCellValue() потом.

Это изменит цикл данных, чтобы он выглядел следующим образом:

// 2. loop through data
for (int i = 0; i < dt.Rows.Count; i++)
{
    IRow row = sheet1.CreateRow(i + 1);
    for (int j = 0; j < dt.Columns.Count; j++)
    {
        ICell cell = row.CreateCell(j);
        string columnName = dt.Columns[j].ToString();
        // Set the cell type
        cell.SetCellType(GetCorrectCellType(dt.Rows[i][columnName].GetType()))
        // Set the cell value
        cell.SetCellValue(dt.Rows[i][columnName]);
    }
}

// Function to return the correct cell type
public int GetCorrectCellType(Type dataType) 
{
   if(dataType == typeof(string))
      return CellType.String;
   else if(dataType == typeof(int) || dataType == typeof(double))
      return CellType.Numeric;
   else if(dataType == typeof(bool))
      return CellType.Boolean;
   else
      return CellType.Unknown; // Not sure how to set Date Type --> Unknown
}

ИЗМЕНИТЬ В этом ответе я обнаружил, как установить значения даты в удобочитаемом формате.

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

Я разработал утилиту Excel с использованием пакета NPOI, которая может

  1. Просто берет вашу таблицу данных или коллекцию
  2. И возвращает вам превосходство, сохраняя при этом все типы данных таблицы/списка в первенстве.

Репозиторий кода Github: https://github.com/ansaridawood/.NET-Generic-Excel-Export-Sample/tree/master/GenericExcelExport/ExcelExport

В поисках объяснения кода вы можете найти его здесь:https://www.codeproject.com/Articles/1241654/Export-to-Excel-using-NPOI-Csharp-and-WEB-API

Он использует NPOI DLL и включает 2 файла cs, и тогда все готово.

Ниже приведен первый файл для справки AbstractDataExport.cs:

      using NPOI.SS.UserModel;
using NPOI.XSSF.UserModel;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;

namespace GenericExcelExport.ExcelExport
{
    public interface IAbstractDataExport
    {
        HttpResponseMessage Export(List exportData, string fileName, string sheetName);
    }

    public abstract class AbstractDataExport : IAbstractDataExport
    {
        protected string _sheetName;
        protected string _fileName;
        protected List _headers;
        protected List _type;
        protected IWorkbook _workbook;
        protected ISheet _sheet;
        private const string DefaultSheetName = "Sheet1";

        public HttpResponseMessage Export
              (List exportData, string fileName, string sheetName = DefaultSheetName)
        {
            _fileName = fileName;
            _sheetName = sheetName;

            _workbook = new XSSFWorkbook(); //Creating New Excel object
            _sheet = _workbook.CreateSheet(_sheetName); //Creating New Excel Sheet object

            var headerStyle = _workbook.CreateCellStyle(); //Formatting
            var headerFont = _workbook.CreateFont();
            headerFont.IsBold = true;
            headerStyle.SetFont(headerFont);

            WriteData(exportData); //your list object to NPOI excel conversion happens here

            //Header
            var header = _sheet.CreateRow(0);
            for (var i = 0; i < _headers.Count; i++)
            {
                var cell = header.CreateCell(i);
                cell.SetCellValue(_headers[i]);
                cell.CellStyle = headerStyle;
            }

            for (var i = 0; i < _headers.Count; i++)
            {
                _sheet.AutoSizeColumn(i);
            }

            using (var memoryStream = new MemoryStream()) //creating memoryStream
            {
                _workbook.Write(memoryStream);
                var response = new HttpResponseMessage(HttpStatusCode.OK)
                {
                    Content = new ByteArrayContent(memoryStream.ToArray())
                };

                response.Content.Headers.ContentType = new MediaTypeHeaderValue
                       ("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
                response.Content.Headers.ContentDisposition = 
                       new ContentDispositionHeaderValue("attachment")
                {
                    FileName = $"{_fileName}_{DateTime.Now.ToString("yyyyMMddHHmmss")}.xlsx"
                };

                return response;
            }
        }

        //Generic Definition to handle all types of List
        public abstract void WriteData(List exportData);
    }
}

и это второй и последний файл AbstractDataExportBridge.cs:

      using NPOI.SS.UserModel;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Text.RegularExpressions;

namespace GenericExcelExport.ExcelExport
{
    public class AbstractDataExportBridge : AbstractDataExport
    {
        public AbstractDataExportBridge()
        {
            _headers = new List<string>();
            _type = new List<string>();
        }

        public override void WriteData<T>(List<T> exportData)
        {
            PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(typeof(T));

            DataTable table = new DataTable();

            foreach (PropertyDescriptor prop in properties)
            {
                var type = Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType;
                _type.Add(type.Name);
                table.Columns.Add(prop.Name, Nullable.GetUnderlyingType(prop.PropertyType) ?? 
                                  prop.PropertyType);
                string name = Regex.Replace(prop.Name, "([A-Z])", " $1").Trim(); //space separated 
                                                                           //name by caps for header
                _headers.Add(name);
            }

            foreach (T item in exportData)
            {
                DataRow row = table.NewRow();
                foreach (PropertyDescriptor prop in properties)
                    row[prop.Name] = prop.GetValue(item) ?? DBNull.Value;
                table.Rows.Add(row);
            }

            IRow sheetRow = null;

            for (int i = 0; i < table.Rows.Count; i++)
            {
                sheetRow = _sheet.CreateRow(i + 1);
                for (int j = 0; j < table.Columns.Count; j++)
                {
                    ICell Row1 = sheetRow.CreateCell(j);

                    string type = _type[j].ToLower();
                    var currentCellValue = table.Rows[i][j];

                    if (currentCellValue != null && 
                        !string.IsNullOrEmpty(Convert.ToString(currentCellValue)))
                    {
                        if (type == "string")
                        {
                            Row1.SetCellValue(Convert.ToString(currentCellValue));
                        }
                        else if (type == "int32")
                        {
                            Row1.SetCellValue(Convert.ToInt32(currentCellValue));
                        }
                        else if (type == "double")
                        {
                            Row1.SetCellValue(Convert.ToDouble(currentCellValue));
                        }
                    }
                    else
                    {
                        Row1.SetCellValue(string.Empty);
                    }
                }
            }
        }
    }
}

Подробное объяснение см. по ссылке, указанной в начале.

Другие вопросы по тегам