팡이네

ClosedXML 사용

C#2017. 5. 17. 15:42

* AddWorksheet() 새로운 워크시트를 만든다.

1
2
3
4
5
6
7
8
9
public IXLWorksheet AddWorksheet(XLWorkbook wb, string sheetName)
{
    var ws = wb.AddWorksheet(sheetName);
    ws.Style.Font.SetFontName("맑은 고딕"); //기본글꼴
    ws.Style.Font.SetFontSize(10);          //기본글꼴크기
    ws.Style.Alignment.Vertical = XLAlignmentVerticalValues.Center; //세로맞춤: 가운데
 
    return ws;
}

* GetExcelColumn() 지정한 컬럼의 엑셀 컬럼문자를 가져온다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public string GetExcelColumn(int columnIndex)
    {
        var colString = "";
 
        if (columnIndex > 26)
        {
            var surplus = columnIndex % 26; if (surplus == 0) surplus = 26;
            var quota = (columnIndex - surplus) / 26;
 
            //3글자 컬럼명
            if (quota > 26)
            {
                var surplus2 = quota % 26;
                var quota2 = (quota - surplus2) / 26;
 
                colString = string.Format("{0}{1}{2}", Convert.ToChar(64 + quota2), Convert.ToChar(64 + surplus2), Convert.ToChar(64 + surplus));
            }
            //2글자 컬럼명
            else
            {
                colString = string.Format("{0}{1}", Convert.ToChar(64 + quota), Convert.ToChar(64 + surplus));
            }
        }
        else
        {
            colString = string.Format("{0}", Convert.ToChar(64 + columnIndex));
        }
 
        return colString;
    }

* AddExcelCell() 지정한 셀에 숫자값을 표시한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public IXLCell AddExcelCell(IXLWorksheet ws, int row, int col, int value, string bgColor
                        , bool bold, XLAlignmentHorizontalValues hAlign)
{
    var cell = ws.Cell(row, col);
    cell.SetValue(value);
    cell.DataType = XLCellValues.Number;
    cell.Style.NumberFormat.Format = "#,##0;(#,##0);-";
    cell.Style.Alignment.Horizontal = hAlign;
    cell.Style.Alignment.Vertical = XLAlignmentVerticalValues.Center;
    cell.Style.Border.OutsideBorder = XLBorderStyleValues.Thin;
    if (bold) cell.Style.Font.Bold = true;
    if (!string.IsNullOrEmpty(bgColor)) cell.Style.Fill.BackgroundColor = XLColor.FromHtml(bgColor);
 
    return cell;
}

* AddExcelCell() 지정한 셀에 문자열을 표시한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
public IXLCell AddExcelCell(IXLWorksheet ws, int row, int col, string value, string bgColor, bool bold
                        , XLAlignmentHorizontalValues hAlign, XLBorderStyleValues outsideBorder)
{
    var cell = ws.Cell(row, col).SetValue(value);
    cell.DataType = XLCellValues.Text;
    cell.Style.Alignment.Horizontal = hAlign;
    cell.Style.Alignment.Vertical = XLAlignmentVerticalValues.Center;
    cell.Style.Border.OutsideBorder = outsideBorder;
    if (bold) cell.Style.Font.Bold = true;
    if (!string.IsNullOrEmpty(bgColor)) cell.Style.Fill.BackgroundColor = XLColor.FromHtml(bgColor);
 
    return cell;
}

* AddExcelCell() 지정한 셀에 문자열을 표시하고 병합한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public IXLRange AddExcelCell(IXLWorksheet ws, int row, int col, int rowSpan, int colSpan, string value, string bgColor, int width)
{
    var endRow = (rowSpan > 1) ? row + rowSpan - 1 : row;
    var endCol = (colSpan > 1) ? col + colSpan - 1 : col;
 
    var rg = ws.Range(row, col, endRow, endCol);
    rg.Merge();
    rg.Cell(1, 1).SetValue(value);
    rg.DataType = XLCellValues.Text;
    rg.Style.Alignment.Horizontal = XLAlignmentHorizontalValues.Center;
    rg.Style.Alignment.Vertical = XLAlignmentVerticalValues.Center;
    rg.Style.Border.OutsideBorder = XLBorderStyleValues.Thin;
    if (!string.IsNullOrEmpty(bgColor)) rg.Style.Fill.BackgroundColor = XLColor.FromHtml(bgColor);
    if (width > 0) rg.FirstCell().WorksheetColumn().Width = width;
 
    return rg;
}
 
public IXLRange AddExcelCell(IXLWorksheet ws, int row, IXLRange range, int rowSpan, int colSpan, string value, string bgColor, int width)
{
    var col = range.Cell(1, 1).WorksheetColumn().ColumnNumber() + range.ColumnCount();
    var endRow = (rowSpan > 1) ? row + rowSpan - 1 : row;
    var endCol = (colSpan > 1) ? col + colSpan - 1 : col;
 
    var rg = ws.Range(row, col, endRow, endCol);
    rg.Merge();
    rg.Cell(1, 1).SetValue(value);
    rg.DataType = XLCellValues.Text;
    rg.Style.Alignment.Horizontal = XLAlignmentHorizontalValues.Center;
    rg.Style.Alignment.Vertical = XLAlignmentVerticalValues.Center;
    rg.Style.Border.OutsideBorder = XLBorderStyleValues.Thin;
    if (!string.IsNullOrEmpty(bgColor)) rg.Style.Fill.BackgroundColor = XLColor.FromHtml(bgColor);
    if (width > 0) rg.FirstCell().WorksheetColumn().Width = width;
 
    return rg;
}

* AddExcelFormularCell() 지정한 셀에 엑셀 수식을 표시한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public IXLCell AddExcelFormularCell(IXLWorksheet ws, int row, int col, string formular, string bgColor, bool bold, string numberFormat)
{
    var cell = ws.Cell(row, col);
    if (!string.IsNullOrEmpty(formular))
    {
        cell.DataType = XLCellValues.Number;
        if (!string.IsNullOrEmpty(numberFormat)) cell.Style.NumberFormat.Format = numberFormat;
        cell.SetFormulaA1(formular);
    }
 
    cell.Style.Alignment.Vertical = XLAlignmentVerticalValues.Center;
    cell.Style.Border.OutsideBorder = XLBorderStyleValues.Thin;
    if (bold) cell.Style.Font.Bold = true;
    if (!string.IsNullOrEmpty(bgColor)) cell.Style.Fill.BackgroundColor = XLColor.FromHtml(bgColor);
 
    return cell;
}

* DownloadExcel() 서버의 엑셀 파일을 다운로드한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
/// <summary>
/// 서버의 엑셀 파일을 다운로드한다.
///     <para>다운로드 후에는 서버의 엑셀 파일을 삭제한다.</para>
/// </summary>
/// <param name="filePath">실제 서버 물리 경로
/// <param name="fileName">엑셀 파일명
public void DownloadExcel(string filePath, string fileName)
{
    //한글 깨어짐 방지
    var saveFileName = HttpUtility.UrlEncode(fileName).Replace("+", "%20");
    //var fullPath = filePath + fileName;
 
    var response = System.Web.HttpContext.Current.Response;
 
    //---------------------------------------------------------------------
    //엑셀 파일 다운로드
    //---------------------------------------------------------------------
    //서버의 엑셀 파일 다운로드 후 몇 바이트 늘어남 -> 엑셀 열기 선택 시 복구 메시지 표시
    //---------------------------------------------------------------------
    //response.ClearContent();
    //response.Clear();
    //response.Charset = "utf-8";
    //response.ContentEncoding = System.Text.Encoding.GetEncoding("utf-8");
    ////response.ContentType = "application/vnd.msexcel";
    //response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
    //response.AddHeader("Content-Disposition", string.Format(@"attachment; filename=""{0}"";", saveFileName));
    ////response.TransmitFile(Server.MapPath("/" + fileName));
    //response.TransmitFile(fullPath);
    //response.Flush();
 
    //엑셀 파일 삭제
    //var deleteFile = new System.IO.FileInfo(fullPath);
    //if (deleteFile.Exists)
    //{
    //  System.IO.File.Delete(fullPath);
    //}
 
    //response.End();
 
    //---------------------------------------------
    //제네릭 처리기 사용
    //---------------------------------------------
    //열기 선택 시 엑셀 파일이 읽기 전용으로 열림
    //---------------------------------------------
    response.Redirect(string.Format("~/DownloadExcelFile.ashx?fileName={0}", saveFileName));
}

* DownloadExcelFile.ashx 파일 내용

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
<%@ WebHandler Language="C#" Class="DownloadExcelFile" %>
 
using System;
using System.IO;
using System.Web;
 
public class DownloadExcelFile : IHttpHandler
{
    public void ProcessRequest(HttpContext context)
    {
        var request = context.Request;
        var response = context.Response;
        var fileName = request.QueryString["fileName"];
 
        if (!string.IsNullOrEmpty(fileName))
        {
            var saveFileName = HttpUtility.UrlEncode(fileName).Replace("+", "%20");
            var fullPath = string.Format("{0}{1}", context.Server.MapPath(@"~/Download/"), fileName);   //다운로드 경로
             
            response.ClearContent();
            response.Clear();
            response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
            response.AddHeader("Content-Disposition", string.Format(@"attachment; filename=""{0}"";", saveFileName));
            response.TransmitFile(fullPath);
            response.Flush();
 
            //엑셀 파일 삭제
            var deleteFile = new FileInfo(fullPath);
            if (deleteFile.Exists)
            {
                File.Delete(fullPath);
            }
             
            response.End();
        }
        else
        {
            var script = "<script type='text/javascript'>alert('엑셀 파일을 찾을 수 없습니다.');history.back();</script>";
            response.Write(script);
            response.End();
        }
    }
 
    public bool IsReusable
    {
        get
        {
            return false;
        }
    }
}

※ 사용방법

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
using(var wb = new new XLWorkbook())
{
    var ws = AddWorksheet(wb, "Test Sheet");
 
    var row = 1;
    var col = 1;
    for (var i = 0; i < list.Length; i++)
    {
        col = 1;
 
        AddExcelCell(ws, row, col++, list[i]["COL1"].ToString());
        AddExcelCell(ws, row, col++, list[i]["COL2"].ToString());
 
        row++;
    }
     
    ws.Columns().AdjustToContents();        //열 너비 자동설정(데이터양이 많을 경우 속도가 매우 느려짐)
    wb.SaveAs(@"d:\\example.xlsx");     //서버의 지정한 경로에 저장
 
    DownloadExcel(@"d:\\example.xlsx"); //서버의 경로에 저장되므로 사용자는 다운로드 필요
}
※ 주의사항
ws.Columns().AdjustToContents();
열 너비 자동설정하는 명령어인데 데이터양이 조금이라도 많을 경우 속도가 매우 느려지므로 조심해서 사용하자.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
사용자 웹 브라우저 및 버전 확인
 
function getBrowserInfo(opt) {
    var ua = navigator.userAgent.toLowerCase();
     
    if (ua.indexOf('android') > -1) return 'Android';
    else if (ua.match(/iphone|ipad|ipot/)) return 'iOS';
     
    if (navigator.appName == 'Microsoft Internet Explorer') {
        if (opt == 'n') return 'Explorer';
        else {
            var re = new RegExp('msie ([0-9]{1,}[\\.0-9]{0,})');
            if (re.exec(ua) !== null) {
                if (opt == 'v')
                    return parseInt(RegExp.$1);
                else
                    return 'Explorer '+ parseInt(RegExp.$1);
            }
        }
    }
    else if (ua.indexOf('trident') != -1 && navigator.product == 'Gecko') { //IE 11 above
        if (opt == 'n') return 'Explorer';
        else {
            var re = new RegExp('trident/.*rv:([0-9]{1,}[\.0-9]{0,})');
            if (re.exec(ua) != null) {
                if (opt == 'v')
                    return parseInt(RegExp.$1);
                else
                    return 'Explorer '+ parseInt(RegExp.$1);
            }
        }
    }
    else if (/edge/.test(ua)) {
        if (opt == 'n') return 'Edge';
        else {
            if (opt == 'v')
                return parseInt(/edge\/([\d\.]+)/.exec(ua)[1]);
            else
                return 'Edge '+ parseInt(/edge\/([\d\.]+)/.exec(ua)[1]);
        }
    }
    else if (/chrome/.test(ua)) {
        if (opt == 'n') return 'Chrome';
        else {
            if (opt == 'v')
                return parseInt(/chrome\/([\d\.]+) safari/.exec(ua)[1]);
            else
                return 'Chrome '+ parseInt(/chrome\/([\d\.]+) safari/.exec(ua)[1]);
        }
    }
    else if (/firefox/.test(ua)) {
        if (opt == 'n') return 'FireFox';
        else {
            if (opt == 'v')
                return parseInt(/firefox\/([\d\.]+)/.exec(ua)[1]);
            else
                return 'FireFox '+ parseInt(/firefox\/([\d\.]+)/.exec(ua)[1]);
        }
    }
    else if (/safari/.test(ua)) {
        if (opt == 'n') return 'Safari';
        else {
            if (opt == 'v')
                return parseInt(/version\/([\d\.]+) safari/.exec(ua)[1]);
            else
                return 'Safari '+ parseInt(/version\/([\d\.]+) safari/.exec(ua)[1]);
        }
    }
     
    return 'Other';
}
 
getBrowserInfo('n');    //웹 브라우저 이름
getBrowserInfo('v');    //웹 브라우저 버전
getBrowserInfo();       //웹 브라우저 이름 + 버전

1. 기본 '텍스트 줄 바꿈' 속성 제외

기본 엑셀 출력 시 모든 셀에 '텍스트 줄 바꿈' 속성이 설정된다.

이를 방지하려면 아래와 같이 스타일을 설정한다.


<style type="text/css">

td { white-space:nowrap; }

</style>



2. 같은 셀에 2줄 표시

만약 특정 셀에서 같은 셀에 2줄 이상을 표시하고 싶을 때가 있다.

이럴 경우에는 아래와 같이 스타일을 설정한다.


<style type="text/css">

br { mso-data-placement:same-cell; }

</style>


Reponse.Write("<td>이번 셀에서는<br/>이 줄은 다음 줄에 표시</td>");


결과


이번 셀에서는

이 줄은 다음 줄에 표시



3. 기본 '텍스트 줄 바꿈' 속성 제외와 같은 셀 2줄 표시를 동시에 하고 싶은 경우

아래와 같이 스타일을 설정한다.


<style type="text/css">

td { white-space:nowrap; }

br { mso-data-placement:same-cell; }

.same { white-space:normal; }

</style>


Reponse.Write("<td>이번 셀에서는<br/>한 줄에 표시</td>");

Reponse.Write(@"<td class=""same"">이번 셀에서는<br/>이 줄은 다음 줄에 표시</td>");


결과


이번 셀에서는한 줄에 표시


이번 셀에서는

이 줄은 다음 줄에 표시



같은 셀에 2줄 이상 표시하려면 '텍스트 줄 바꿈' 속성이 설정되어야 하므로

원하는 셀에 same css를 설정하여 같은 셀에 표시할 수 있도록 해준다.



4. 숫자 형식 지정(자릿점 표시)

원하는 셀에 다음과 같이 스타일을 지정한다.


//number가 문자열인 경우에도 강제 지정

Response.Write(string.Format(@"<td style=""mso-number-format:'#,###';"">{0}</td>", number));


또는 


//number가 숫자형식인 경우만 제대로 표시

Response.Write(string.Format("<td>{0:N0}"</td>, number));



5. 강제 문자열 형식 지정(숫자도 문자처럼 표시)


Response.Write(string.Format(@"<td style=""mso-number-format:'@';"">{0}</td>", string));



6. 한글 인코딩 설정


Response.Charset = "UTF-8";

Response.ContentEncoding = System.Text.Encoding.GetEncoding("utf-8");