■ Open XML SDK 2.0을 사용해 엑셀 XLSX 파일 내보내기 예제

----------------------------------------------------------------------------------------------------

using System;

using System.Data;

using System.Windows.Forms;

 

namespace TestProject

{

    /// <summary>

    /// 메인 폼

    /// </summary>

    public partial class MainForm : Form

    {

        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor

        ////////////////////////////////////////////////////////////////////////////////////////// Public

 

        #region 생성자 - MainForm()

 

        /// <summary>

        /// 생성자

        /// </summary>

        public MainForm()

        {

            InitializeComponent();

        }

 

        #endregion

 

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method

        ////////////////////////////////////////////////////////////////////////////////////////// Private

 

        #region Export 버튼 클릭시 처리하기 - exportButton_Click(sender, e)

 

        /// <summary>

        /// Export 버튼 클릭시 처리하기

        /// </summary>

        /// <param name="sender">이벤트 발생자</param>

        /// <param name="e">이벤트 인자</param>

        private void exportButton_Click(object sender, EventArgs e)

        {

            DateTime startTime = DateTime.Now;

 

            DataTable sourceTable1 = GetSampleTable();

            DataTable sourceTable2 = GetSampleTable();

 

            DataSet sourceSet = new DataSet();

 

            sourceSet.Tables.Add(sourceTable1);

            sourceSet.Tables.Add(sourceTable2);

 

            ExcelHelper.CreateExcelDocument(sourceSet, "c:\\result.xlsx", 1, 1);

 

            DateTime endTime = DateTime.Now;

 

            MessageBox.Show("경과 시간 : " + (endTime - startTime).ToString());

        }

 

        #endregion

 

 

        #region 샘플 테이블 구하기 - GetSampleTable()

 

        /// <summary>

        /// 샘플 테이블 구하기

        /// </summary>

        /// <returns>샘플 테이블</returns>

        private DataTable GetSampleTable()

        {

            DataTable table = new DataTable();

 

            table.Columns.Add("항목1", typeof(string));

            table.Columns.Add("항목2", typeof(string));

            table.Columns.Add("항목3", typeof(string));

            table.Columns.Add("항목4", typeof(string));

            table.Columns.Add("항목5", typeof(string));

 

            for(int i = 1; i <= 1000000; i++)

            {

                table.Rows.Add("A" + i.ToString(), "B" + i.ToString(), "C" + i.ToString(), "D" + i.ToString(), "E" + i.ToString());

            }

 

            table.AcceptChanges();

 

            return table;

        }

 

        #endregion

    }

}

----------------------------------------------------------------------------------------------------

 

■ Open XML SDK 2.0을 사용해 엑셀 XLSX 파일 내보내기

----------------------------------------------------------------------------------------------------

using System;

using System.Collections.Generic;

using System.Data;

using System.Reflection;

 

using DocumentFormat.OpenXml.Packaging;

using DocumentFormat.OpenXml.Spreadsheet;

using DocumentFormat.OpenXml;

 

namespace TestProject

{

    /// <summary>

    /// 엑셀 헬퍼

    /// </summary>

    public static class ExcelHelper

    {

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method

        ////////////////////////////////////////////////////////////////////////////////////////// Static

        //////////////////////////////////////////////////////////////////////////////// Public

 

        #region 엑셀 문서 생성하기 - CreateExcelDocument(sourceSet, xlsxFilePath, startRowIndex, startColumnIndex)

 

        /// <summary>

        /// 엑셀 문서 생성하기

        /// </summary>

        /// <param name="sourceSet">소스 셋</param>

        /// <param name="xlsxFilePath">XLSX 파일 경로</param>

        /// <param name="startRowIndex">시작 행 인덱스</param>

        /// <param name="startColumnIndex">시작 컬럼 인덱스</param>

        /// <returns>처리 결과</returns>

        public static bool CreateExcelDocument(DataSet sourceSet, string xlsxFilePath, uint startRowIndex, int startColumnIndex)

        {

            try

            {

                using(SpreadsheetDocument spreadsheetDocument = SpreadsheetDocument.Create(xlsxFilePath, SpreadsheetDocumentType.Workbook))

                {

                    WriteExcelFile(sourceSet, spreadsheetDocument, startRowIndex, startColumnIndex);

                }

 

                return true;

            }

            catch

            {

                return false;

            }

        }

 

        #endregion

 

        #region 엑셀 문서 생성하기 - CreateExcelDocument(sourceTable, xlsxFilePath, startRowIndex, startColumnIndex)

 

        /// <summary>

        /// 엑셀 문서 생성하기

        /// </summary>

        /// <param name="sourceTable">소스 테이블</param>

        /// <param name="xlsxFilePath">XLSX 파일 경로</param>

        /// <param name="startRowIndex">시작 행 인덱스</param>

        /// <param name="startColumnIndex">시작 컬럼 인덱스</param>

        /// <returns>처리 결과</returns>

        public static bool CreateExcelDocument(DataTable sourceTable, string xlsxFilePath, uint startRowIndex, int startColumnIndex)

        {

            DataSet set = new DataSet();

 

            set.Tables.Add(sourceTable);

 

            bool result = CreateExcelDocument(set, xlsxFilePath, startRowIndex, startColumnIndex);

 

            set.Tables.Remove(sourceTable);

 

            return result;

        }

 

        #endregion

 

        #region 엑셀 문서 생성하기 - CreateExcelDocument<T>(sourceList, xlsxFilePath, startRowIndex, startColumnIndex)

 

        /// <summary>

        /// 엑셀 문서 생성하기

        /// </summary>

        /// <typeparam name="T">소스 리스트 타입</typeparam>

        /// <param name="sourceList">소스 리스트</param>

        /// <param name="xlsxFilePath">XLSX 파일 경로</param>

        /// <param name="startRowIndex">시작 행 인덱스</param>

        /// <param name="startColumnIndex">시작 컬럼 인덱스</param>

        /// <returns>처리 결과</returns>

        public static bool CreateExcelDocument<T>(List<T> sourceList, string xlsxFilePath, uint startRowIndex, int startColumnIndex)

        {

            DataSet sourceSet = new DataSet();

 

            sourceSet.Tables.Add(GetDataTable(sourceList));

 

            return CreateExcelDocument(sourceSet, xlsxFilePath, startRowIndex, startColumnIndex);

        }

 

        #endregion

 

        //////////////////////////////////////////////////////////////////////////////// Private

 

        #region 엑셀 컬럼명 구하기 - GetExcelColumnName(columnIndex)

 

        /// <summary>

        /// 엑셀 컬럼명 구하기

        /// </summary>

        /// <param name="columnIndex">컬럼 인덱스</param>

        /// <returns>엑셀 컬럼명</returns>

        private static string GetExcelColumnName(int columnIndex)

        {

            // columnIndex Excel Column Name

            // ----------- -----------------

            // 0           A

            // 1           B

            // 25          Z

            // 26          AA

            // 27          AB

 

            if(columnIndex < 26)

            {

                return ((char)('A' + columnIndex)).ToString();

            }

 

            char firstCharacter  = (char)('A' + (columnIndex / 26) - 1);

            char secondCharacter = (char)('A' + (columnIndex % 26));

 

            return string.Format("{0}{1}", firstCharacter, secondCharacter);

        }

 

        #endregion

 

        #region 텍스트 셀 추가하기 - AppendTextCell(excelRow, cellReference, cellStringValue)

 

        /// <summary>

        /// 텍스트 셀 추가하기

        /// </summary>

        /// <param name="excelRow">엑셀 행</param>

        /// <param name="cellReference">셀 참조</param>

        /// <param name="cellStringValue">셀 문자열 값</param>

        private static void AppendTextCell(Row excelRow, string cellReference, string cellStringValue)

        {

            Cell      cell      = new Cell() { CellReference = cellReference, DataType = CellValues.String };

            CellValue cellValue = new CellValue();

 

            cellValue.Text = cellStringValue;

 

            cell.Append(cellValue);

 

            excelRow.Append(cell);

        }

 

        #endregion

 

        #region 숫자 셀 추가하기 - AppendNumericCell(excelRow, cellReference, cellStringValue)

 

        /// <summary>

        /// 숫자 셀 추가하기

        /// </summary>

        /// <param name="excelRow">엑셀 행</param>

        /// <param name="cellReference">셀 참조</param>

        /// <param name="cellStringValue">셀 문자열 값</param>

        private static void AppendNumericCell(Row excelRow, string cellReference, string cellStringValue)

        {

            Cell      cell      = new Cell() { CellReference = cellReference };

            CellValue cellValue = new CellValue();

 

            cellValue.Text = cellStringValue;

 

            cell.Append(cellValue);

 

            excelRow.Append(cell);

        }

 

        #endregion

 

        #region 엑셀 워크시트에 데이터 테이블 쓰기 - WriteDataTableToExcelWorksheet(sourceTable, worksheetPart, startRowIndex,

            startColumnIndex)

 

        /// <summary>

        /// 엑셀 워크시트에 데이터 테이블 쓰기

        /// </summary>

        /// <param name="sourceTable">소스 테이블</param>

        /// <param name="worksheetPart">워크시트 파트</param>

        /// <param name="startRowIndex">시작 행 인덱스</param>

        /// <param name="startColumnIndex">시작 컬럼 인덱스</param>

        /// <remarks>시작 행 인덱스 및 시작 컬럼 인덱스는 1부터 시작한다.</remarks>

        private static void WriteDataTableToExcelWorksheet(DataTable sourceTable, WorksheetPart worksheetPart, uint startRowIndex,

            int startColumnIndex)

        {

            Worksheet worksheet = worksheetPart.Worksheet;

            SheetData sheetData = worksheet.GetFirstChild<SheetData>();

 

            // 데이터 테이블에서 각 컬럼의 데이터를 위한 헤더를 포함하는, 헤더 행을 엑셀 파일에 생성한다.

            // 각 컬럼의 데이터가 무슨 타입인지를 나타내는 (텍스트 또는 숫자), 배열을 또한 생성한다.

            // 그래서 실제 셀의 데이터를 쓰게 될 때, 텍스트 값들 또는 숫자 셀 값들을 쓰는지 알게 된다.

            int      columnCount          = sourceTable.Columns.Count;

            bool[]   isNumericColumnArray = new bool[columnCount];

            string[] excelColumnNameArray = new string[columnCount];

 

            for(int i = 0; i < columnCount; i++)

            {

                excelColumnNameArray[i] = GetExcelColumnName(i + startColumnIndex - 1);

            }

 

            // 엑셀 워크시트에 헤더 행을 생성한다.

            uint rowIndex = startRowIndex;

 

            Row headerRow = new Row { RowIndex = rowIndex };

 

            sheetData.Append(headerRow);

 

            for(int columnIndex = 0; columnIndex < columnCount; columnIndex++)

            {

                DataColumn dataColumn = sourceTable.Columns[columnIndex];

 

                AppendTextCell(headerRow, excelColumnNameArray[columnIndex] + rowIndex.ToString(), dataColumn.ColumnName);

 

                isNumericColumnArray[columnIndex] = (dataColumn.DataType.FullName == "System.Decimal") ||

                    (dataColumn.DataType.FullName == "System.Int32");

            }

 

            // 데이터 테이블에서 각 행의 데이터를 단계적으로 작성한다.

            string cellValue        = string.Empty;

            double numericCellValue = 0;

 

            foreach(DataRow dataRow in sourceTable.Rows)

            {

                // 신규 행을 생성하고, 이 행의 데이터 집합을 추가한다.

                ++rowIndex;

 

                Row newExcelRow = new Row { RowIndex = rowIndex };

 

                sheetData.Append(newExcelRow);

 

                for(int columnIndex = 0; columnIndex < columnCount; columnIndex++)

                {

                    cellValue = dataRow.ItemArray[columnIndex].ToString();

 

                    // 데이터를 갖고 셀을 생성한다.

                    if(isNumericColumnArray[columnIndex])

                    {

                        // 숫자 셀들을 위해, 입력 데이터가 숫자인지 확인한 다음, 엑셀 파일에 작성한다.

                        // 숫자 값이 NULL인 경우, 엑셀 파일에 아무 것도 작성하지 않는다.

                        numericCellValue = 0;

 

                        if(double.TryParse(cellValue, out numericCellValue))

                        {

                            cellValue = numericCellValue.ToString();

 

                            AppendNumericCell(newExcelRow, excelColumnNameArray[columnIndex] + rowIndex.ToString(), cellValue);

                        }

                    }

                    else

                    {

                        // 텍스트 셀들을 위해, 입력 데이터를 엑셀 파일에 바로 작성한다.

                        AppendTextCell(newExcelRow, excelColumnNameArray[columnIndex] + rowIndex.ToString(), cellValue);

                    }

                }

            }

        }

 

        #endregion

 

        #region 엑셀 파일 쓰기 - WriteExcelFile(sourceSet, spreadsheetDocument, startRowIndex, startColumnIndex)

 

        /// <summary>

        /// 엑셀 파일 쓰기

        /// </summary>

        /// <param name="sourceSet">소스 셋</param>

        /// <param name="spreadsheetDocument">스프레드 시트 문서</param>

        /// <param name="startRowIndex">시작 행 인덱스</param>

        /// <param name="startColumnIndex">시작 컬럼 인덱스</param>

        private static void WriteExcelFile(DataSet sourceSet, SpreadsheetDocument spreadsheetDocument, uint startRowIndex, int startColumnIndex)

        {

            // 엑셀 파일 내용들을 생성한다.

            // 이 함수는 엑셀 파일을 생성할 뿐만 아니라 파일에 쓰거나, 또는 MemoryStream에 작성할 때 사용된다.

            spreadsheetDocument.AddWorkbookPart();

 

            spreadsheetDocument.WorkbookPart.Workbook = new DocumentFormat.OpenXml.Spreadsheet.Workbook();

 

            // 엑셀 2010에서 충돌을 방지해준다.

            spreadsheetDocument.WorkbookPart.Workbook.Append(new BookViews(new WorkbookView()));

 

            // "WorkbookStylesPart"를 추가하지 않는 경우, OLEDB가 이 .xlsx 파일에 접속하는 것을 거부할 것이다.

            WorkbookStylesPart workbookStylesPart = spreadsheetDocument.WorkbookPart.AddNewPart<WorkbookStylesPart>("rIdStyles");

 

            Stylesheet stylesheet = new Stylesheet();

 

            workbookStylesPart.Stylesheet = stylesheet;

 

            // 데이터 셋에 있는 데이터 테이블들 각각을 통해 루프를 돌면서, 각 데이터 테이블을 위한 신규 엑셀 워크시트를 생성한다.

            uint worksheetNumber = 1;

 

            foreach(DataTable sourceTable in sourceSet.Tables)

            {

                string workSheetID   = "rId" + worksheetNumber.ToString();

                string worksheetName = sourceTable.TableName;

 

                WorksheetPart newWorksheetPart = spreadsheetDocument.WorkbookPart.AddNewPart<WorksheetPart>();

 

                newWorksheetPart.Worksheet = new DocumentFormat.OpenXml.Spreadsheet.Worksheet();

 

                // 시트 데이터를 생성한다.

                newWorksheetPart.Worksheet.AppendChild(new DocumentFormat.OpenXml.Spreadsheet.SheetData());

 

                // 워크시트를 저장한다.

                WriteDataTableToExcelWorksheet(sourceTable, newWorksheetPart, startRowIndex, startColumnIndex);

 

                newWorksheetPart.Worksheet.Save();

 

                // 워크북 관계에 대한 워크시트를 생성한다.

                if(worksheetNumber == 1)

                {

                    spreadsheetDocument.WorkbookPart.Workbook.AppendChild(new DocumentFormat.OpenXml.Spreadsheet.Sheets());

                }

 

                spreadsheetDocument.WorkbookPart.Workbook.GetFirstChild<DocumentFormat.OpenXml.Spreadsheet.Sheets>().AppendChild

                (

                    new DocumentFormat.OpenXml.Spreadsheet.Sheet()

                    {

                        Id      = spreadsheetDocument.WorkbookPart.GetIdOfPart(newWorksheetPart),

                        SheetId = (uint)worksheetNumber,

                        Name    = sourceTable.TableName

                    }

                );

 

                worksheetNumber++;

            }

 

            spreadsheetDocument.WorkbookPart.Workbook.Save();

        }

 

        #endregion

 

 

        #region 널 가능 타입 구하기 - GetNullableType(sourceType)

 

        /// <summary>

        /// 널 가능 타입 구하기

        /// </summary>

        /// <param name="sourceType">소스 타입</param>

        /// <returns>널 가능 타입</returns>

        private static Type GetNullableType(Type sourceType)

        {

            Type targetType = sourceType;

 

            if(sourceType.IsGenericType && sourceType.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))

            {

                targetType = Nullable.GetUnderlyingType(sourceType);

            }

 

            return targetType;

        }

 

        #endregion

 

        #region 널 가능 타입 여부 구하기 - IsNullableType(sourceType)

 

        /// <summary>

        /// 널 가능 타입 여부 구하기

        /// </summary>

        /// <param name="sourceType">소스 타입</param>

        /// <returns>널 가능 타입 여부</returns>

        private static bool IsNullableType(Type sourceType)

        {

            return (sourceType == typeof(string) || sourceType.IsArray ||

                (sourceType.IsGenericType && sourceType.GetGenericTypeDefinition().Equals(typeof(Nullable<>))));

        }

 

        #endregion

 

        #region 데이터 테이블 구하기 - GetDataTable<T>(list)

 

        /// <summary>

        /// 데이터 테이블 구하기

        /// </summary>

        /// <typeparam name="T">리스트 타입</typeparam>

        /// <param name="list">리스트</param>

        /// <returns>데이터 테이블</returns>

        private static DataTable GetDataTable<T>(List<T> list)

        {

            DataTable targetTable = new DataTable();

 

            foreach(PropertyInfo propertyInfo in typeof(T).GetProperties())

            {

                targetTable.Columns.Add(new DataColumn(propertyInfo.Name, GetNullableType(propertyInfo.PropertyType)));

            }

 

            foreach(T item in list)

            {

                DataRow dataRow = targetTable.NewRow();

 

                foreach(PropertyInfo propertyInfo in typeof(T).GetProperties())

                {

                    if(!IsNullableType(propertyInfo.PropertyType))

                    {

                        dataRow[propertyInfo.Name] = propertyInfo.GetValue(item, null);

                    }

                    else

                    {

                        dataRow[propertyInfo.Name] = (propertyInfo.GetValue(item, null) ?? DBNull.Value);

                    }

                }

 

                targetTable.Rows.Add(dataRow);

            }

 

            return targetTable;

        }

 

        #endregion

    }

}

----------------------------------------------------------------------------------------------------

※ 첨부 Open XML SDK 2.0 for Microsoft Office 설치 후 Visual Studio에서 DocumentFormat.OpenXml 참조를 설정한다.

Posted by 사용자 icodebroker
TAG

댓글을 달아 주세요