Excel 장표 출력을 어떻게 만들까 - COM 자동화 / Open XML / 템플릿 방식의 판단표

· 업데이트: · · Excel, 장표, Windows 개발, Office, COM, Open XML

수정 이력(1건, 최종 수정 2026년 09월 01일)

이 글에 적용한 변경 사항의 기록입니다. 보관해 둔 수정 전 버전은 DOI가 부여된 고정 URL에서 읽을 수 있습니다.

일본어 원문의 완역으로 다시 번역했습니다. 기존 한국어판은 원문의 일부만 옮긴 축약본이라 절, 표, Mermaid 그림, 그림 설명, FAQ가 빠져 있었습니다. 일본어 원문에 맞춰 이들을 모두 복원했고, 기술적인 주장은 일본어판과 같습니다. 수정 전 버전 보기 (DOI: 10.5281/zenodo.21635175)
최초 공개
이 글을 인용하기(DOI: 10.5281/zenodo.21635174)

이 글은 Zenodo에 보관되어 있습니다. 항상 최신 버전으로 연결되는 DOI와 지금 보고 있는 버전에 고정된 DOI를 아래에 함께 제시합니다.

小村 豪 (2026). 「Excel 장표 출력을 어떻게 만들까 - COM 자동화 / Open XML / 템플릿 방식의 판단표」. 합동회사 코무라소프트. https://doi.org/10.5281/zenodo.21635174 https://comcomponent.com/ko/blog/2026/03/16/010-excel-report-output-how-to-build/

DOI(최신 버전)
10.5281/zenodo.21635174
DOI(이 버전)
10.5281/zenodo.22217456

Excel 장표 출력 상담에서는 「Excel로 내고 싶다」는 말 속에 실은 서로 다른 요건이 여러 개 섞여 있는 경우가 드물지 않습니다.

  • 사용자가 나중에 직접 수정하고 싶다
  • 지금 있는 .xlsm을 남기고 싶다
  • 피벗, 그래프, 인쇄 설정까지 그대로 쓰고 싶다
  • 야간 배치로 대량으로 내고 싶다
  • 서버에서 무인 실행하고 싶다
  • PDF도 필요하다

이런 요건들은 한 가지 방식으로 전부 깔끔하게 풀리지 않습니다. 가장 먼저 봐야 하는 것은 라이브러리 이름보다도, Excel 애플리케이션을 움직일 것인가, Excel 파일을 만들 것인가입니다.

여기를 잘못 잡으면 처음에는 돌아가더라도 나중에 유지보수가 힘들어집니다. 이번에는 Windows 앱이나 업무 시스템에서의 Excel 장표 출력을 전제로, COM 자동화 / Open XML / 템플릿 삽입 / 기존 VBA 병용의 선택 방법을 정리합니다.

가장 먼저 봐야 할 갈림길Excel 장표 출력에서는 라이브러리 이름보다 먼저 Excel 애플리케이션을 움직일 것인가 Excel 파일을 만들 것인가라는 갈림길을 봐야 하며, 여기를 잘못 잡으면 처음에는 돌아가더라도 나중에 유지보수가 힘들어짐을 보여주는 그림.애플리케이션을 움직인다파일을 만든다Excel 애플리케이션을 움직일까, 파일을 만들까Excel을 자동 조작하는 방식xlsx를 직접 조립하는 방식잘못 잡으면 나중에 유지보수가 힘들어진다

그림 1: 라이브러리를 고르기 전에 조작할 것인지 조립할 것인지를 정한다.

대상 독자와 전제

업무 시스템에서 Excel 장표를 내보내는 방식을 앞으로 정할 개발자를 대상으로 씁니다.

전제로 두는 것은 Windows에서 동작하는 C# / .NET 앱이나 배치에서 출력하는 구성입니다. 기존 VBA 자산을 안고 있는 경우도 상정하고 있지만, 그 경우에도 「VBA만으로 완결시킨다」가 아니라 .NET 쪽과 역할을 나누는 것을 전제로 씁니다. 코드 예제는 C# / .NET 8입니다.

먼저 짚어 둘 용어

용어 의미
Open XML Office 2007 이후의 파일 형식입니다. .xlsx의 실체는 XML 파일을 모은 ZIP 압축 파일이며, Excel을 기동하지 않아도 프로그램에서 조립할 수 있습니다
COM 자동화 (Office Automation) Excel 같은 Office 앱을 실제로 기동해 외부 프로그램에서 조작하는 방식입니다. COM은 Windows의 컴포넌트 간 호출 체계이며, Excel은 그 창구를 공개하고 있습니다
bitness 32bit와 64bit 중 어느 쪽으로 빌드·실행되는가입니다. COM 자동화에서는 호출하는 쪽과 Excel 본체의 bitness가 맞지 않으면 연결에 실패합니다
이름 정의 범위 Excel에서 셀이나 셀 범위에 붙이는 이름입니다. Cells[12, 7] 같은 번지 대신 이 이름을 통해 데이터를 넣을 위치를 지정할 수 있습니다
테이블 (ListObject) Excel의 「표 서식 지정」으로 만드는 구조입니다. 행을 추가하면 서식과 수식이 자동으로 늘어나므로 명세의 입구로 적합합니다

1. 먼저 결론

먼저 결론만 나열해 둡니다.

  • 사용자가 나중에 Excel을 열어 편집하는 장표라면 제1 후보는 템플릿 + .xlsx / .xlsm 직접 생성입니다.
  • 서버 / 서비스 / 스케줄러에서 자동 생성한다면 Office 자동화를 전제로 하지 않는 편이 안전합니다.
  • 기존의 .xlsm, VBA, 그래프, 피벗, 인쇄 설정을 살리고 싶다면 레이아웃과 Excel 고유 기능은 템플릿 쪽에 모으고, 코드는 데이터 삽입에만 집중하는 편이 잘 부서지지 않습니다.
  • 정말로 Excel 앱의 동작 그 자체가 필요할 때만 COM 자동화를 데스크톱상의 유인 실행으로 한정해서 쓰는 것이 자연스럽습니다.
  • 단순한 목록 출력이라면 처음부터 CSV / PDF / 웹 화면 쪽이 요건에 맞는 경우도 꽤 많습니다.

요컨대, 많은 업무 장표에서는 「Excel을 조작한다」가 아니라 「Excel 파일을 조립한다」쪽이 자연스럽습니다.

요건에서 본 제1 후보사용자가 나중에 편집하는 장표는 템플릿과 직접 생성이 제1 후보이고, 서버나 서비스에서의 자동 생성은 Office 자동화를 전제로 하지 않으며, 정말로 Excel 앱의 동작이 필요할 때만 COM 자동화를 유인 실행으로 한정해서 씀을 보여주는 그림.나중에 편집하는 장표템플릿과 직접 생성무인 자동 생성Office 자동화를 전제로 하지 않는다Excel의 동작 그 자체가 필요COM 자동화를 유인 실행으로 한정

그림 2: 누가 어디서 돌리는지를 보면 제1 후보는 거의 정해진다.

이 글의 지식 맵

Excel 장표 출력은 Excel 앱을 조작할 것인가, Excel 파일을 직접 조립할 것인가에 따라 설계가 크게 갈립니다. 무인 서버에서의 COM 자동화는 Microsoft가 비지원이라고 명시하고 있으며, 야간 배치나 대량 출력에서는 Open XML SDK나 ClosedXML, NPOI, EPPlus에 의한 직접 생성이 적합합니다. 이용자가 나중에 편집하는 장표는 겉모습을 템플릿에 남기고 이름 정의 범위나 테이블에 값을 삽입하는 방식이 제1 후보이며, ReportModel·Template·Binder·Finisher의 4층으로 나누면 셀 번지 의존이나 레이아웃 변경의 영향을 억제할 수 있습니다. 저장은 임시 파일에 다 쓴 뒤 FileMode.CreateNew와 File.Move로 안전하게 바꿔 달며, 명세가 넘친 경우에는 조용히 잘라내지 않고 예외로 멈추는 것이 실무상의 요점입니다.

Excel 장표 출력 만드는 방법COM 자동화·xlsx 직접 생성·템플릿 삽입·기존 VBA 병용·Graph API라는 장표 출력의 구현 방식을 구분해 쓰는 것과, ReportModel/Template/Binder/Finisher의 4층 구성, 안전한 파일 저장 패턴의 관계를 보여주는 그림이용한다이용한다권장되는 대응사용은 비권장이용한다이용한다이용한다이용한다이용한다이용한다이용한다이용한다이용한다이용한다전제로 한다전제로 한다전제로 한다이용한다방지한다이용한다방지한다방지한다사용은 비권장전제로 한다사용은 비권장이용한다이용한다이용한다이용한다Excel 장표 출력템플릿 삽입 방식Excel COM 자동화(Excel COM Interop).xlsx 직접 생성서버 사이드 Office 자동화ClosedXMLOpen XML SDKNPOIEPPlus명명된 범위테이블(ListObject)Binder 계층ReportModel 계층Template 레이어Finisher 계층임시 파일 경유 안전 저장 패턴중간에 끊긴 파일의 잔류 위험FileMode.CreateNew동일 이름 파일의 조용한 덮어쓰기 위험명세 초과 예외 처리명세의 조용한 잘림 위험셀 주소 하드코딩Excel 시트 1개의 상한(1,048,576행×16,384열)Microsoft Graph Excel API기존 VBA 자산 유지 방식

그림의 실선은 항상 성립하는 관계, 점선은 조건이 붙는 관계입니다(성립 조건은 상세 페이지의 관계별 설명에 적혀 있습니다). 관계 전체 목록(총 29건, 근거와 확신도 포함)과 주요 개념의 정의는 지식 맵 상세 페이지에 정리되어 있습니다(일본어). 데이터: JSON-LD / Turtle

2. 가장 먼저 정할 것

Excel 장표 출력에서 가장 먼저 정해 두고 싶은 것을 표로 정리합니다.

확인 항목 먼저 정하는 이유
최종 산출물은 .xlsx / .xlsm / PDF / CSV 중 무엇인가 여기서 방식을 꽤 좁힐 수 있습니다
사용자는 출력 후에 Excel에서 편집하는가 편집이 전제라면 Excel 기능과 레이아웃 유지가 중요합니다
실행 장소는 사용자 PC인가, 서버 / 서비스 / 배치인가 COM 자동화를 쓸 수 있는 범위가 크게 달라집니다
기존 VBA / 매크로 / 애드인을 남길 것인가 .xlsm 템플릿이나 단계적 이행 설계가 필요합니다
그래프, 피벗, 인쇄 범위, 머리글 / 바닥글까지 고정하고 싶은가 코드보다 템플릿으로 모으는 편이 잘 부서지지 않습니다
1회당 행 수, 파일 수, 동시 실행 수는 어느 정도인가 대량 출력에서는 COM보다 직접 생성이 더 어울립니다
장표의 겉모습은 누가 변경하는가 개발자뿐 아니라 현장도 건드린다면 템플릿 방식이 잘 맞습니다

3. 주요 구현 방식

3.1 Excel COM 자동화

Excel을 기동하고 Workbook, Worksheet, Range를 COM을 통해 조작하는 방식입니다. 진짜 Excel을 운전하는 방식이라고 생각하면 이해하기 쉽습니다.

강점은 Excel 고유의 동작을 그대로 쓸 수 있다는 점입니다. 기존 통합 문서, 그래프, 피벗, 인쇄 설정, 매크로, PDF 출력 등과 잘 어울리며, 「최종적으로 Excel이 어떻게 보여줄 것인가」를 그대로 다룰 수 있습니다.

다만 약점도 뚜렷합니다.

  • Excel 설치가 필요
  • 프로세스 수명, 파일 잠금, 대화상자, bitness, 사용자 프로파일 의존을 안고 있음
  • 무인 서버나 서비스로부터의 Office Automation은 Microsoft 자체가 권장·지원하지 않음

세 번째는 이 글에서 가장 강한 주장이므로 근거를 명시해 둡니다. Microsoft의 지원 문서 「Considerations for server-side Automation of Office」에는 서버 사이드에서의 Office Automation을 권장하지도 지원하지도 않는다는 내용이 명시되어 있습니다. 이유로 꼽히는 것은 다음 5가지입니다.

이유 내용
사용자 ID Office는 사용자의 존재를 전제로 하며, 사용자별 레지스트리 설정을 읽으러 갑니다. 사용자 프로파일이 없는 계정으로 동작하는 서비스는 여기서 실패합니다
데스크톱의 상호작용성 Office는 상호작용 가능한 데스크톱을 전제로 하며, 모달 대화상자를 띄우는 경우가 있습니다. 아무도 닫을 수 없는 환경에서는 스레드가 그 자리에서 계속 멈춥니다
재진입과 확장성 Office 앱은 단일 스레드 COM 서버로, 재진입이 불가능합니다. 단일 클라이언트를 위한 설계이므로 서버 용도에 필요한 다중 실행을 견디지 못합니다
견고성과 안정성 최초 사용 시 설치 기능이 예기치 않은 대화상자를 띄울 수 있으며, 애초에 서버 사이드 배포에서의 테스트가 이루어지지 않았습니다
서버 사이드 보안 분산 컴포넌트를 위한 보안 제어를 갖추고 있지 않아 요청을 인증하지 않습니다. 캐시된 자격 증명이 여러 클라이언트 사이에서 공유될 위험이 있습니다

Microsoft 365의 RPA 환경에 대해서는 별도로 「Considerations for unattended automation of Office」에 정리되어 있습니다. 방식 선정에서 이 점이 쟁점이 될 때는 이 두 문서를 출처로 삼으십시오.

서버 사이드 자동화의 위치무인 서버나 서비스로부터의 Office Automation은 Microsoft 자체가 권장도 지원도 하지 않으며, 방식 선정에서 쟁점이 될 때는 지원 문서와 RPA 환경 문서 두 가지를 출처로 삼을 수 있음을 보여주는 그림.무인 서버로부터의 Office AutomationMicrosoft가 권장도 지원도 하지 않음지원 문서가 근거가 된다M365의 RPA 환경은 별도 문서로 정리

그림 3: 이 방식의 가부는 취향이 아니라 공식 출처로 판가름 난다.

3.2 .xlsx 직접 생성

.xlsx는 Open XML 형식이므로 Excel을 기동하지 않고 파일을 직접 조립할 수 있습니다. Open XML SDK 같은 수단을 쓰면 프로그램 쪽에서 통합 문서, 시트, 셀, 스타일, 테이블을 조작할 수 있습니다.

이 방식의 강점은 Excel이 설치되지 않은 환경에서도 돌리기 쉽고, 배치나 서버와 잘 어울린다는 점입니다.

한편 Excel 그 자체가 가진 UI 쪽 동작까지 자연스럽게 재현하고 싶을 때는 조금 힘들어집니다. 열 너비 자동 조정, 페이지 분할, 복잡한 겉모습, 기존 통합 문서의 깊은 편집 등을 코드만으로 전부 깔끔하게 하려고 하면 코드량이 점점 늘어납니다.

직접 생성 방식의 성격xlsx는 Open XML 형식이므로 Excel을 기동하지 않고 직접 조립할 수 있어 Excel 미설치 환경이나 배치, 서버와 잘 어울리는 한편, Excel의 UI 쪽 동작까지 재현하려 하면 코드가 늘어남을 보여주는 그림.xlsx는 Open XML 형식Excel을 기동하지 않고 조립배치나 서버와 잘 어울림UI 쪽 재현은 코드가 늘어남

그림 4: Excel이 필요 없다는 강점과 겉모습 재현의 약점은 표리 관계다.

.NET에서 .xlsx를 다루는 라이브러리는 몇 가지 있으며, 라이선스 조건이 실무에서 중요하게 작용합니다. 자주 후보에 오르는 것은 다음과 같습니다.

라이브러리 라이선스 위치
Open XML SDK (DocumentFormat.OpenXml) MIT Microsoft 제작. Open XML의 구조를 거의 그대로 다룹니다. 할 수 있는 일은 가장 넓은 대신, 셀 하나를 쓰는 데도 코드량이 필요합니다
ClosedXML MIT Open XML SDK의 래퍼입니다. 워크시트, 셀, 이름 정의 범위, 테이블을 직관적인 API로 다룰 수 있습니다. .xlsx.xlsm을 지원하며 Excel 설치가 필요 없습니다
NPOI Apache License 2.0 Java의 Apache POI를 .NET으로 이식한 것입니다. .xls라는 오래된 형식도 다룰 수 있는 것이 특징입니다
EPPlus 버전 5 이후로는 Polyform Noncommercial 또는 상용 라이선스 고기능이지만 상용 이용에는 유상 라이선스가 필요합니다. 버전 4계열의 LGPL 시절 기억으로 선택하면 라이선스 면에서 사고가 납니다

템플릿 삽입 방식이라면 겉모습은 템플릿 쪽이 가지므로, 코드에 요구되는 것은 「정해진 입구에 값을 넣는」것뿐입니다. 그래서 코드량이 적은 래퍼 계열이 다루기 쉬워집니다.

3.3 템플릿 삽입

실무에서 가장 권장하기 쉬운 것은 Excel 템플릿을 먼저 만들고, 코드는 데이터 삽입에만 집중하는 방식입니다.

장표의 겉모습, 수식, 조건부 서식, 인쇄 범위, 머리글 / 바닥글, 로고, 그래프는 템플릿 쪽에 둡니다. 코드 쪽은 템플릿을 복제하고, 이름 정의 범위, 테이블, 셀 범위 같은 「정해진 입구」에 데이터를 씁니다.

이렇게 하면 레이아웃 수정과 업무 로직 수정이 분리됩니다. Excel 장표에서 흔히 보이는 Cells[37, 9] = ... 지옥을 꽤 피하기 쉬워집니다.

템플릿 삽입의 역할 분담장표의 겉모습이나 수식, 인쇄 설정은 템플릿 쪽에 두고, 코드 쪽은 템플릿을 복제해 이름 정의 범위나 테이블이라는 정해진 입구로 데이터를 씀으로써 레이아웃 수정과 업무 로직 수정이 분리됨을 보여주는 그림.템플릿 쪽겉모습·수식·인쇄 설정을 보유코드 쪽정해진 입구에 값을 쓰기만 함레이아웃 수정과 업무 수정이 분리됨

그림 5: 겉모습과 로직의 자리를 나누는 것이 이 방식의 핵심이다.

3.4 기존 VBA 자산을 남기는 방식

기존의 .xlsm이나 VBA가 살아 있다면 전부를 한 번에 다시 만들지 않는 편이 자연스러운 경우가 많습니다. 장표의 UI나 마지막 정형은 VBA에 남기고, 무거운 계산이나 DB / HTTP / 업무 로직은 C# / .NET 쪽으로 옮기는 분할 방식은 꽤 현실적입니다.

이때 중요한 것은 책임을 애매하게 하지 않는 것입니다.

  • VBA 쪽은 통합 문서 안의 동작
  • .NET 쪽은 데이터 취득과 업무 처리
  • 양쪽의 경계는 이름 정의 범위, 테이블, 공개 인터페이스 등으로 고정
기존 VBA와 .NET의 책임 분담기존의 xlsm과 VBA를 남기는 경우 VBA 쪽은 통합 문서 안의 동작을, .NET 쪽은 데이터 취득과 업무 처리를 맡고, 양쪽의 경계를 이름 정의 범위나 테이블, 공개 인터페이스로 고정함을 보여주는 그림.VBA 쪽통합 문서 안의 동작.NET 쪽데이터 취득과 업무 처리경계는 이름 정의 범위 등으로 고정

그림 6: 자산을 남기는 요령은 경계를 고정해 책임을 애매하게 하지 않는 것이다.

3.5 Microsoft 365 / Graph를 쓰는 경우

Excel 파일이 처음부터 OneDrive / SharePoint 위에 있고, 웹 앱이나 모바일 앱에서 공동으로 이용하고 싶다면 Microsoft Graph의 Excel API도 선택지에 들어옵니다.

다만 로컬 PC상의 임의 파일을 대충 양산하는 일반적인 해법은 아닙니다. 권한, 저장 위치, 세션, 운영이 처음부터 M365를 전제로 하게 됩니다.

3.6 애초에 Excel일 필요가 있는가

장표의 요건이 「사람이 나중에 만지는 표」라면 Excel을 선택하는 것은 자연스럽습니다. 다만 다음과 같은 요건이라면 다른 형식 쪽이 더 단순한 경우도 많습니다.

  • 인쇄해서 보관한다 -> PDF
  • 다른 시스템에 취합한다 -> CSV / TSV / JSON
  • 브라우저에서 보기만 하면 된다 -> HTML / 웹 화면
  • 집계와 시각화가 주목적 -> BI나 대시보드
Excel일 필요가 있는지 확인장표의 요건이 사람이 나중에 만지는 표라면 Excel을 선택하는 것이 자연스럽지만, 인쇄 보관이나 다른 시스템으로의 취합, 브라우저 열람, 집계와 시각화가 주목적이라면 다른 형식이 더 단순한 경우도 많음을 보여주는 그림.만진다만지지 않는다사람이 나중에 만지는 표인가Excel을 선택하는 것이 자연스럽다다른 형식을 검토한다PDF / CSV / 웹 화면 / BI 등

그림 7: 출력 형식은 목적에서 역산하며, Excel을 기본값으로 삼지 않는다.

4. 방식 비교

방식의 차이를 한 장의 표로 정리하면 다음과 같습니다.

방식 Excel 설치 무인 실행과의 궁합 기존 레이아웃 재사용 Excel 고유 기능과의 궁합 잘 맞는 상황
COM 자동화 필요 약함 강함 매우 강함 사용자 PC에서의 출력, 기존 .xlsm, 최종 PDF화
.xlsx 직접 생성 불필요 강함 배치, 서버, 대량 출력
템플릿 삽입 불필요(출력 시) 강함 강함 중~강 많은 업무 장표의 제1 후보
기존 VBA 병용 이용 형태에 따름 약함~중 매우 강함 강함 단계적 이행, 기존 자산 활용
Graph Excel API M365 전제 OneDrive / SharePoint상의 공동 이용

5. 흔한 요건별 선택법

5.1 사용자 PC에서 출력하고 그대로 편집한다

이 경우는 템플릿 + 직접 생성이 꽤 유력합니다. 사용자는 출력 후에 Excel로 열기 때문에 최종 편집은 Excel에 맡겨도 되기 때문입니다.

5.2 야간 배치나 서비스에서 대량 생성한다

야간 배치가 얽힌다면 먼저 COM 자동화를 제외하는 데서부터 시작하는 편이 안전합니다. 생성은 .xlsx의 직접 생성으로 옮기고, 필요하면 나중에 사용자가 Excel로 여는 형태로 만듭니다.

야간 배치에서의 진행 방식야간 배치나 서비스에서의 대량 생성에서는 먼저 COM 자동화를 후보에서 제외하고, 생성을 xlsx의 직접 생성으로 옮기며, 필요하면 나중에 사용자가 Excel로 여는 형태로 만드는 것이 안전함을 보여주는 그림.야간 배치로 대량 생성하고 싶다먼저 COM 자동화를 제외한다xlsx의 직접 생성으로 옮긴다필요하면 사용자가 나중에 연다

그림 8: 무인 실행 설계는 빼기부터 시작하는 것이 안전하다.

5.3 기존의 .xlsm / VBA를 살리고 싶다

기존 자산이 살아 있다면 템플릿으로 .xlsm을 남기고, 데이터 삽입만 밖에서 하는 것이 현실적입니다.

5.4 명세 행이 크다

Excel 1시트의 상한은 1,048,576행 × 16,384열입니다. 명세가 큰 경우에는 먼저 다음을 정해 둡니다.

  • 몇 행을 넘으면 시트를 분할할 것인가
  • 몇 건을 넘으면 파일을 분할할 것인가
  • 애초에 CSV 쪽이 더 자연스럽지 않은가
명세가 클 때 먼저 정할 것Excel 1시트에는 행 수와 열 수의 상한이 있으므로, 명세가 큰 경우에는 몇 행에서 시트를 분할할 것인지, 몇 건에서 파일을 분할할 것인지, 애초에 CSV 쪽이 더 자연스럽지 않은지를 먼저 정해 둠을 보여주는 그림.명세가 크다1시트의 상한이 있다시트 분할 기준을 정한다파일 분할 기준을 정한다CSV 쪽이 자연스러운지 재검토한다

그림 9: 상한에 부딪히고 나서 생각하지 말고 분할 방침을 먼저 정한다.

6. 실무에서 권장하기 쉬운 구성

실무에서 잘 부서지지 않는 것은 다음 4층으로 나눈 구성입니다.

역할 여기서 안 하는 것
ReportModel 장표에 필요한 값을 정형 셀 번지를 모름
Template 겉모습, 수식, 인쇄 설정, 그래프를 보유 DB나 업무 로직을 모름
Binder 이름 정의 범위 / 테이블에 데이터를 씀 비즈니스 판단을 끌어들이지 않음
Finisher 필요하다면 VBA / COM / PDF화를 수행 원본 데이터 취득을 하지 않음

이 분할의 좋은 점은 코드가 Excel의 겉모습에 끌려가기 어려워진다는 것입니다.

6.1 층 사이를 흐르는 것

중요한 것은 층의 경계를 넘는 것이 무엇인가입니다. 이것이 정해져 있으면 레이아웃 변경과 업무 로직 변경을 따로 진행할 수 있습니다.

원본 데이터복제한 통합 문서이름과 값의 짝값이 들어간 통합 문서산출물Finisher가 필요 없으면여기서 완성DB / API / 파일ReportModel장표에 필요한 값만을정형해 보유한다Templatexlsx 또는 xlsm겉모습·수식·인쇄 설정Binder이름 정의 범위와 테이블에값을 쓴다FinisherPDF화나 VBA 호출 등필요할 때만xlsx / xlsm / PDF

그림 10: 4층 사이를 흐르는 것은 이름과 값의 짝뿐이며, 셀 번지는 Binder 밖으로 나가지 않는다.

경계를 넘는 것은 이름과 값의 짝뿐이며, 셀 번지는 Binder보다 바깥으로 내보내지 않습니다. 템플릿의 사정이 ReportModel까지 전해진다면, 그 시점에서 설계가 무너지기 시작한 것입니다.

6.2 최소 구현 예제

템플릿 삽입을 ClosedXML로 작성하면 다음과 같습니다. 템플릿 Invoice.xlsx 쪽에는 미리 Rpt_Title, Rpt_IssuedOn, Rpt_CustomerName, Rpt_DetailRows라는 이름 정의 범위를 정의해 둡니다.

// C# / .NET 8 + ClosedXML(MIT 라이선스)
//   dotnet add package ClosedXML
using ClosedXML.Excel;

// ReportModel에 해당. 셀 번지는 일절 갖지 않는다
var rows = new (string Code, string Name, int Qty, decimal UnitPrice)[]
{
    ("A-100", "볼 베어링", 12, 480m),
    ("A-205", "샤프트", 3, 12800m),
    ("B-010", "장착 브래킷", 30, 260m),
};

const string TemplatePath = @"templates\Invoice.xlsx";
string outputDir = "output";
Directory.CreateDirectory(outputDir);

// 파일명을 「초 단위 시각」으로 만들지 말 것. 1건씩 도는 배치에서는
// 2건이 같은 초에 들어간 순간 같은 이름이 되어, 나중에 저장한 쪽이
// 앞선 장표를 덮어씁니다. 사라진 것을 아무도 눈치채지 못하는 것이 성가신 점입니다.
// 장표를 유일하게 결정하는 업무상의 식별자(여기서는 청구서 번호)를 반드시 넣습니다.
string invoiceNo = "INV-2026-000123";     // 호출하는 쪽에서 받는다
string outputPath = Path.Combine(outputDir, $"Invoice_{invoiceNo}.xlsx");

// 1. 템플릿을 연다. 저장은 다른 이름으로 하므로 템플릿 자체는 바뀌지 않는다
using var workbook = new XLWorkbook(TemplatePath);

// 2. 헤더는 이름 정의 셀로. 코드에 셀 번지가 나오지 않는 것이 핵심
workbook.Cell("Rpt_Title").Value = "청구서";
workbook.Cell("Rpt_IssuedOn").Value = DateTime.Today;   // 값으로 넣는다. 표시 형식은 템플릿 쪽
workbook.Cell("Rpt_CustomerName").Value = "샘플 주식회사";

// 3. 명세는 이름 정의 범위를 입구로 삼아 범위 내 상대 위치로 쓴다
var detail = workbook.Range("Rpt_DetailRows");
if (rows.Length > detail.RowCount())
{
    // 준비한 행 수를 초과했다. 조용히 잘라내지 말고 여기서 멈춘다
    throw new InvalidOperationException(
        $"명세가 {rows.Length}건 있지만, 템플릿의 Rpt_DetailRows는 {detail.RowCount()}행입니다." +
        "템플릿 쪽의 행 수를 늘리거나 시트를 분할하십시오.");
}

for (int i = 0; i < rows.Length; i++)
{
    var row = rows[i];
    detail.Cell(i + 1, 1).Value = row.Code;        // 범위 내 1부터 시작하는 상대 위치
    detail.Cell(i + 1, 2).Value = row.Name;
    detail.Cell(i + 1, 3).Value = row.Qty;
    detail.Cell(i + 1, 4).Value = row.UnitPrice;
}

// 4. 다른 이름으로 저장한다. 템플릿은 읽기 전용 자산으로 남긴다.
//    쓰기는 같은 폴더의 임시 파일에 수행하고, 다 쓴 뒤에 본래 이름으로
//    바꿔 답니다. outputPath에 직접 쓰면, 도중에 실패했을 때(디스크 가득 참,
//    통합 문서의 불일치 등) 「도중까지 쓰인 .xlsx」가 업무상의 파일명으로 남습니다
string tempPath = Path.Combine(
    Path.GetDirectoryName(outputPath) ?? string.Empty,   // 이름 바꾸기를 같은 볼륨 안에 두기 위함
    $".{Path.GetFileName(outputPath)}.{Guid.NewGuid():N}.tmp");

try
{
    using (var stream = new FileStream(tempPath, FileMode.CreateNew, FileAccess.Write, FileShare.None))
    {
        workbook.SaveAs(stream);
    }

    // 이미 같은 이름이 있으면 IOException. 같은 이름이 왔을 때 조용히 덮어쓰지 않고
    // 그 자리에서 알아챌 수 있습니다(FileMode.CreateNew와 같은 방침)
    File.Move(tempPath, outputPath);
}
catch
{
    // 실패하면 흔적을 남기지 않는다. 남기면 다음 실행이 같은 이름으로 재시도하지 못하게 된다
    try { File.Delete(tempPath); } catch (IOException) { }
    throw;
}
Console.WriteLine($"출력했습니다: {outputPath}");

이 코드에서 의식하고 있는 점은 5가지입니다.

  • 셀 번지가 코드에 나오지 않는다. 삽입 대상은 이름 정의 범위뿐입니다. 템플릿의 행을 1행 늘려도 이 코드는 바뀌지 않습니다
  • 템플릿을 덮어쓰지 않는다. 연 통합 문서는 반드시 다른 이름으로 저장합니다
  • 날짜와 숫자를 값으로 넣고 있다. 문자열로 정형해서 넣으면 Excel 쪽에서 정렬도 집계도 할 수 없게 됩니다
  • 명세가 넘치면 예외로 멈춘다. 조용히 잘라내는 것이 장표에서 가장 나쁜 고장 방식입니다. 5.4의 방침을 여기서 구현으로 옮깁니다
  • 다 쓰고 나서 본래의 이름을 붙인다. SaveAs는 쓰기 시작한 뒤에 실패할 수 있습니다. 디스크가 가득 찼다, 공유가 끊겼다, 통합 문서의 내용이 부정확했다 ── 어느 것이든 일어납니다. outputPath에 직접 쓰고 있으면, 그때 남는 것은 Invoice_INV-2026-000123.xlsx라는 완벽한 이름의, 도중에 끊긴 파일입니다. 사람은 이름으로 판단하므로 이것을 완성된 장표와 구별할 수 없습니다. 게다가 FileMode.CreateNew는 기존 파일을 거부하므로 재실행해도 「이미 있다」로 멈춥니다. 임시 파일에 쓴 뒤 File.Move로 바꿔 달면, 그 이름이 나타나는 것은 내용물이 갖춰졌을 때뿐이 됩니다. 바꿔 다는 곳을 같은 폴더로 하는 것은 볼륨을 넘나드는 Move가 복사가 되어 도중에 끊길 수 있기 때문입니다

금액을 decimal로 갖고 있어도 Excel 파일 형식에 들어가는 시점에서 배정밀도 부동소수점이 됩니다. 반올림 기준이 업무상 중요하다면 Excel의 수식에 맡기지 말고 ReportModel 쪽에서 반올림을 마친 값을 만드는 편이 안전합니다.

.xlsm을 템플릿으로 삼는 경우도 흐름은 같지만, 저장할 확장자를 .xlsm에 맞춥니다. 매크로를 남긴 채 삽입하고 싶은 구성은 3.4와 같습니다.

임시 파일을 거치는 저장 흐름저장은 같은 폴더의 임시 파일에 다 쓴 뒤 File.Move로 본래 이름으로 바꿔 달고, 실패하면 임시 파일을 지움으로써 도중에 끊긴 파일이 업무상의 파일명으로 남는 것을 막는 흐름을 보여주는 그림.성공실패같은 폴더의 임시 파일에 쓴다다 썼는가File.Move로 본래 이름으로 바꿔 단다임시 파일을 지우고 예외를 전달한다이름이 나타나는 것은 내용물이 갖춰졌을 때뿐

그림 11: 업무상의 파일명은 완성된 파일에만 붙인다.

7. 빠지기 쉬운 곳

7.1 셀 번지를 업무 사양으로 삼지 않는다

Cells[12, 7]이 업무 규칙을 나타내기 시작하면 레이아웃 변경이 그대로 사양 변경이 됩니다. 코드는 이름 정의 범위나 테이블 이름을 통해 장표를 만지는 편이 오래갑니다.

셀 번지를 업무 사양으로 삼지 않는다셀 번지가 업무 규칙을 나타내기 시작하면 레이아웃 변경이 그대로 사양 변경이 되므로, 코드는 이름 정의 범위나 테이블 이름을 통해 장표를 만지는 편이 오래감을 보여주는 그림.셀 번지가 업무 규칙을 나타낸다레이아웃 변경이 사양 변경이 된다이름 정의 범위나 테이블 이름을 통한다레이아웃을 바꿔도 코드가 유지된다

그림 12: 번지가 아니라 이름으로 만지는 것이 장표 코드의 수명을 결정한다.

7.2 병합 셀을 데이터의 입구로 삼지 않는다

병합 셀은 겉모습을 위한 기능입니다. 삽입 대상으로 쓰면 행 추가나 범위 계산에서 사고가 나기 쉽습니다.

7.3 숫자나 날짜를 「겉모습 붙은 문자열」로 채우지 않는다

값은 값으로 넣고, 겉모습은 셀 서식으로 옮기는 편이 자연스럽습니다.

7.4 템플릿 변경을 비공식 운영으로 만들지 않는다

템플릿은 코드는 아니지만 실질적으로는 사양 그 자체입니다. 버전 관리, 차분 확인, 리뷰 대상으로 다루는 것이 무난합니다.

7.5 COM을 쓴다면 bitness와 수명 관리를 가볍게 보지 않는다

COM 자동화나 VBA 연계에서는 32bit / 64bit의 차이, Excel 프로세스의 뒤처리, 파일 잠금, 사용자 환경 차이가 은근히 영향을 미칩니다.

8. 정리

Excel 장표 출력은 「Excel로 낸다」는 한 줄로 끝나는 이야기처럼 보이지만, 실제로는 몇 가지 분기를 먼저 정해야 합니다.

  • Excel 애플리케이션을 움직일 것인가
  • Excel 파일을 만들 것인가
  • 사용자 PC인가, 무인 실행인가
  • 기존 VBA나 .xlsm을 남길 것인가
  • 최종 산출물은 Excel인가, PDF나 CSV인가

실무에서의 제1 후보로는 템플릿 + 직접 생성이 꽤 강력합니다. 거기에 필요에 따라 기존 VBA의 재사용이나 사용자 PC상에서의 최종 Excel 처리를 더하는 형태가 정리하기 좋습니다.

정리하기 좋은 구성을 만드는 법실무에서는 템플릿과 직접 생성을 제1 후보로 두고, 거기에 필요에 따라 기존 VBA의 재사용이나 사용자 PC상에서의 최종 Excel 처리를 더해 가는 형태가 정리하기 좋음을 보여주는 그림.템플릿과 직접 생성을 축으로 둔다필요하면 기존 VBA 재사용을 더한다필요하면 사용자 PC에서의 최종 처리를 더한다

그림 13: 축을 하나 정하고 예외만 더해 가면 정리하기 좋다.

9. 참고 자료

읽는 순서대로 나열했습니다.

9.1 방식을 정하기 전에 읽을 것

9.2 직접 생성에서 쓰는 것

  • About the Open XML SDK for Office.xlsx를 Excel 없이 조립하는 토대입니다
  • ClosedXML — 6.2의 코드 예제에서 쓰고 있는 래퍼입니다. MIT 라이선스
  • NPOI — 오래된 .xls도 다룰 필요가 있는 경우의 선택지입니다. Apache License 2.0
  • EPPlus — 버전 5 이후의 라이선스 조건을 채택 전에 반드시 확인하십시오

9.3 M365 / SharePoint상에서 다루는 경우

9.4 큰 통합 문서를 다룰 때 더 파고들 것

같은 태그를 공유하는 최신 기사입니다. 더 가까운 주제로 지식을 넓힐 수 있습니다.

이 기사와 가까운 토픽 페이지입니다. 기사를 출발점 삼아 관련 서비스와 다른 기사로 이어집니다.

ActiveX 이관

COM / ActiveX / OCX 자산을 유지할지, 감쌀지, 교체할지의 단계적 판단을 정리한 토픽 페이지입니다.

이 기사는 다음 서비스 페이지로 이어집니다. 가까운 입구부터 확인해 주세요.

자주 묻는 질문

이 기사 주제에 대해 상담 시 자주 나오는 질문을 모았습니다.

Excel 장표 출력은 COM 자동화와 파일 직접 생성 중 어느 쪽을 선택해야 하나요?
가장 먼저 봐야 할 것은 라이브러리 이름이 아니라 Excel 애플리케이션을 움직일 것인가, Excel 파일을 만들 것인가입니다. 많은 업무 장표에서는 「Excel을 조작한다」가 아니라 「Excel 파일을 조립한다」쪽이 자연스러우며, 사용자가 나중에 편집하는 장표라면 템플릿 + .xlsx/.xlsm 직접 생성이 제1 후보입니다. 정말로 Excel 애플리케이션의 동작 그 자체가 필요할 때만 COM 자동화를 데스크톱상의 유인 실행으로 한정해서 쓰는 것이 자연스럽습니다.
서버나 야간 배치에서 Excel의 COM 자동화를 써도 되나요?
피하는 편이 안전합니다. 무인 서버나 서비스로부터의 Office Automation은 Microsoft 자체가 권장·지원하지 않습니다. COM 자동화는 Excel 설치가 필요한 데다 프로세스 수명, 파일 잠금, 대화상자, bitness, 사용자 프로파일 의존 같은 문제를 안고 있습니다. 야간 배치나 대량 출력에서는 .xlsx의 직접 생성으로 옮기고, 필요하면 나중에 사용자가 Excel로 여는 형태로 만드는 것이 안전합니다.
기존의 .xlsm이나 VBA 자산을 남긴 채로 장표 출력을 만들 수 있나요?
만들 수 있습니다. 기존 자산이 살아 있다면 전부를 한 번에 다시 만들지 말고, .xlsm을 템플릿으로 남기고 데이터 삽입만 밖에서 하는 것이 현실적입니다. 장표의 UI나 마지막 정형은 VBA에 남기고, 무거운 계산이나 DB·HTTP·업무 로직은 C#/.NET 쪽으로 옮기는 분할 방식이 쓰기 좋습니다. 중요한 것은 책임을 애매하게 하지 않는 것이며, 양쪽의 경계는 이름 정의 범위, 테이블, 공개 인터페이스 등으로 고정합니다.
Excel 장표 구현에서 피해야 할 함정은 무엇인가요?
셀 번지를 업무 사양으로 삼지 않는 것이 먼저 중요하며, Cells[12, 7] 같은 번지 지정이 아니라 이름 정의 범위나 테이블 이름을 통해 장표를 만지는 편이 오래갑니다. 병합 셀은 겉모습을 위한 기능이므로 삽입 대상으로 쓰지 않는다, 숫자나 날짜는 값으로 넣고 겉모습은 셀 서식으로 옮긴다, 템플릿은 실질적으로 사양이므로 버전 관리·리뷰 대상으로 다룬다는 점도 효과가 있습니다. 또한 Excel 한 시트의 상한은 1,048,576행×16,384열이므로, 명세가 큰 경우에는 시트 분할이나 파일 분할 방침을 먼저 정해 둡니다.

저자 프로필

기사 저자의 프로필 페이지입니다.

Go Komura

합동회사 코무라소프트 대표

Windows 소프트웨어 개발, 기술 상담, 장애 조사를 중심으로 재현이 어려운 장애 조사와 기존 자산이 남아 있는 프로젝트에 강점이 있습니다.

블로그 목록으로 돌아가기