简体   繁体   中英

Export Excel using Npoi

I am looking to export an excel sheet using NPOI library. Is there any way to insert the datatable into the sheet without losing the data format?

Previously, I used to use the Gembox Spreadsheet Library. This worked well for me. The code for that looke like:

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

I had to stop using the Gembox library because I need to make excel files with more than 5 sheets. Gembox, unfortunately does not allow that on a free platform. As such, I've switched to NPOI.

Now that I'm using the NPOI library, I've change my code to:

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

The problem that I'm encountering with using the NPOI library is, all the cells in the exported excel file is formatted as text. I'd like to retain the format that's used in the data table. Looking for help. Thanks in advance!!!

To insert data from a data table, you could perhaps use this code in place of the comment " // How can i insert the data's from dataTable in this sheet ".

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

For data types, you could use the function cell.SetCellType(CellType.[TYPE HERE]); . The type entered in the function SetCellType must match the data type in cell.SetCellValue() afterwards.

This will modify the data loop to look as follows:

// 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
}

EDIT I found how set set Date values in a human readable format in this answer .

I know I am a little late here but I think it may help others, yes, there is a way to convert datatable directly to export excel without losing data format.

I have developed an excel utility with the use of the NPOI package, which can

  1. Simply takes your data table or the collection
  2. And Returns you excel while maintaining all the data table/list data type intact in the excel.

Github Code repo.: https://github.com/ansaridawood/.NET-Generic-Excel-Export-Sample/tree/master/GenericExcelExport/ExcelExport

Looking for a code explanation, you can find it here: https://www.codeproject.com/Articles/1241654/Export-to-Excel-using-NPOI-Csharp-and-WEB-API

It uses NPOI DLL and it has 2 cs files to include and then you are good to go

Below is the first file for reference 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);
    }
}

and this the second and final file 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);
                    }
                }
            }
        }
    }
}

For a detailed explanation, refer link provided in the beginning.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM