자세한 내용은 하단의 내 업데이트를 참조하십시오.
때로는 일부 데이터를 Excel 파일 (xlsx 형식)로 출력해야하는 프로젝트가 있습니다. 프로세스는 일반적으로 다음과 같습니다.
-
사용자가 내 응용 프로그램에서 일부 버튼을 클릭
-
내 코드는 DB 쿼리를 실행하고 결과를 어떻게 든 처리합니다.
-
내 코드는 Excel com interop 라이브러리 또는 일부 타사 라이브러리 (예 : Aspose.Cells)를 사용하여 * .xlsx 파일을 생성합니다.
온라인 에서이 작업을 수행하는 방법에 대한 코드 예제를 쉽게 찾을 수 있지만 더 강력한 방법을 찾고 있습니다. 코드를 유지 관리하고 쉽게 이해할 수 있도록 몇 가지 디자인 원칙을 따르도록 코드를 만들고 싶습니다.
xlsx 파일을 생성하려는 초기 시도는 다음과 같습니다.
var wb = new Workbook();
var ws = wb.Worksheets[0];
ws.Cells[0, 0].Value = "Header";
ws.Cells[1, 0].Value = "Row 1";
ws.Cells[2, 0].Value = "Row 2";
ws.Cells[3, 0].Value = "Row 3";
wb.Save(path);
장점 : 많지 않습니다. 작동하므로 좋습니다.
단점 :
- 셀 참조는 하드 코딩되어 있으므로 코드 전체에 마법의 숫자가 흩어져 있습니다.
- 많은 셀 참조를 업데이트하지 않고 열과 행을 추가하거나 제거하기가 어렵습니다.
- 타사 라이브러리를 배워야합니다. 일부 라이브러리는 다른 라이브러리와 같이 사용되지만 여전히 문제가있을 수 있습니다. com interop 라이브러리가 1 기반 셀 참조를 사용하는 반면 Aspose.Cells는 0 기반 셀 참조를 사용하는 문제가있었습니다.
다음은 위에 나열된 단점 중 일부를 해결하는 솔루션입니다. 데이터 테이블을 셀 조작으로 파고 다른 셀 참조를 방해하지 않고 이동하고 변경할 수있는 자체 객체로 취급하고 싶었습니다. 의사 코드는 다음과 같습니다.
var headers = new Block(new string[] { "Col 1", "Col 2", "Col 3" });
var body = new Block(new string[,]
{
{ "Row 1", "Row 1", "Row 1" },
{ "Row 2", "Row 2", "Row 2" },
{ "Row 3", "Row 3", "Row 3" }
});
body.PutBelow(headers);
이 솔루션의 일부로 Blocks 컨테이너를 가져 와서 데이터를 * .xlsx 파일로 출력하는 데 필요한 셀 조작을 수행하는 BlockEngine 객체가 있습니다. 블록 객체에는 서식이 첨부 될 수 있습니다.
장점 :
- 이렇게하면 초기 코드에 있던 대부분의 매직 넘버가 제거됩니다.
- 내가 언급 한 BlockEngine 객체에는 여전히 셀 조작이 필요하지만 많은 셀 조작 코드가 숨겨져 있습니다.
- 스프레드 시트의 다른 부분에 영향을주지 않고 행을 추가하고 제거하는 것이 훨씬 쉽습니다.
단점 :
- 열을 추가하거나 제거하기는 여전히 어렵습니다. 열 2와 3의 위치를 바꾸려면 셀 내용을 직접 바꿔야합니다. 이 경우 편집은 8 회이므로 실수를 할 기회는 8 회입니다.
- 이 두 열에 대한 서식이 있으면 업데이트해야합니다.
- 이 솔루션은 수평 블록 배치를 지원하지 않습니다. 한 블록 만 다른 블록 아래에 놓을 수 있습니다. 물론 가질 수는
tableRight.PutToRightOf(tableLeft)
있지만 tableRight와 tableLeft의 행 수가 다른 경우 문제가 발생할 수 있습니다. 테이블을 배치하려면 엔진이 다른 모든 테이블을 인식해야합니다. 이것은 나에게 불필요하게 복잡해 보인다. - 블록 객체와 BlockEngine을 통한 추상화 계층을 통해 코드가 처음 시도하는 것보다 타사 라이브러리에 덜 밀접하게 연결되어 있지만 여전히 타사 코드를 알아야합니다. 느슨하게 결합 된 다양한 형식 옵션을 지원하려면 많은 코드를 작성해야 할 것입니다. 내 BlockEngine은 큰 혼란입니다.
다른 경로를 취하는 솔루션이 있습니다. 과정은 다음과 같습니다.
-
보고서 데이터를 가져 와서 선택한 형식으로 xml 파일을 생성합니다.
-
그런 다음 xsl 변환을 사용하여 xml 파일을 Excel 2003 XML 스프레드 시트 파일로 변환합니다.
-
거기에서 타사 라이브러리를 사용하여 xml Spreadsheet를 xlsx 파일로 간단히 변환합니다.
비슷한 프로세스를 설명하고 코드 예제가 포함 된 이 페이지 를 찾았습니다 .
장점 :
- 이 솔루션은 거의 세포 조작이 필요하지 않습니다. 대신 xsl / xpath를 사용하여 조작을 수행하십시오. 테이블에서 두 개의 열을 교환하려면 셀 교환이 필요한 다른 솔루션과 달리 xsl 파일의 전체 열을 이동합니다.
- Excel 2003 XML 스프레드 시트를 xlsx 파일로 변환 할 수있는 타사 라이브러리는 여전히 필요하지만 라이브러리가 필요한 모든 것입니다. 써드 파티 라이브러리를 호출하는 데 필요한 코드의 양은 아주 적습니다.
- 이 솔루션은 이해하기 쉽고 가장 적은 양의 코드가 필요하다고 생각합니다.
- 내 XML 형식으로 데이터를 작성하는 코드는 간단합니다.
- xsl 파일은 Excel 2003 XML 스프레드 시트가 복잡하기 때문에 복잡합니다. 그러나 xsl 파일의 출력을 쉽게 확인할 수 있습니다. Excel에서 출력을 열고 오류 메시지를 확인하십시오.
- 샘플 Excel 2003 XML 스프레드 시트 파일을 쉽게 생성 할 수 있습니다. 원하는 xlsx 파일과 같은 스프레드 시트를 만든 다음 Excel 2003 XML 스프레드 시트로 저장하면됩니다.
단점 :
- Excel 2003 XML 스프레드 시트는 특정 기능을 지원하지 않습니다. 예를 들어 열 너비를 자동 맞춤 할 수 없습니다. 머리글이나 바닥 글에는 이미지를 포함 할 수 없습니다. 결과 xlsx 파일을 pdf로 내보내려는 경우 pdf 책갈피를 설정할 수 없습니다. (셀 주석을 사용 하여이 문제를 해결했습니다.). 타사 라이브러리를 사용하여이 작업을 수행해야합니다.
- Excel 2003 XML 스프레드 시트를 지원하는 라이브러리가 필요합니다.
- 11 년 된 MS Office 파일 형식을 사용합니다.
참고 : xlsx 파일은 실제로 xml 파일을 포함하는 zip 파일이지만 xml 형식은 내 목적으로는 너무 복잡해 보입니다.
마지막으로 SSRS와 관련된 솔루션을 살펴 보았지만 내 목적으로는 너무 부풀어 보입니다.
내 첫 질문으로 돌아가서 코드로 Excel 파일을 생성하기위한 좋은 디자인 패턴은 무엇입니까? 나는 몇 가지 해결책을 생각할 수 있지만 이상적인 것으로 생각되는 것은 없습니다. 각각 단점이 있습니다.
업데이트 : 그래서 비슷한 XLSX 파일을 생성하기 위해 BlockEngine 솔루션과 XML Spreadsheet 솔루션을 모두 시도했습니다. 그들의 의견은 다음과 같습니다.
-
BlockEngine 솔루션 :
- 대안을 고려할 때 너무 많은 코드가 필요합니다.
- 오프셋이 잘못되면 한 블록을 다른 블록으로 덮어 쓰는 것이 너무 쉽다는 것을 알았습니다.
- 원래는 블록 수준에서 서식을 첨부 할 수 있다고 언급했습니다. 블록 내용과 별도로 서식을 지정하는 것보다 낫지 않다는 것을 알았습니다. 내용과 서식을 결합하는 좋은 방법을 생각할 수 없습니다. 그것들을 분리 할 수있는 좋은 방법도 찾을 수 없습니다. 그냥 엉망입니다.
-
XML 스프레드 시트 솔루션 :
- 지금은이 솔루션으로 갈 것입니다.
- 이 솔루션에는 훨씬 적은 코드가 필요하다는 점을 반복해야합니다. BlockEngine을 Excel 자체로 효과적으로 대체하고 있습니다. 여전히 책갈피 및 페이지 나누기와 같은 기능에 대한 해킹이 필요합니다.
- XML 스프레드 시트 형식은 까다 롭지 만, 약간의 변경 작업을 수행하고 선호하는 Diff 프로그램의 기존 파일과 결과를 쉽게 비교할 수 있습니다. 그리고 일단 당신이 특이성을 알아 낸 후에는 그것을 제자리에 놓고 잊어 버릴 수 있습니다.
- 여전히이 솔루션이 이전 Excel 파일 형식에 의존하고 있다고 걱정합니다.
- 내가 만든 XSLT 파일은 작업하기 쉽습니다. 여기서는 형식을 다루는 것이 BlockEngine 솔루션보다 훨씬 간단합니다.
답변
정말로 당신에게 잘 맞는 것을 원한다면, “불필요하게 복잡한”아이디어에 익숙해지는 것이 좋습니다. 이것이 Microsoft Office 파일 형식을 다루는 특성입니다.
나는 “블록들”에 대한 당신의 생각을 좋아합니다 … 테이블과 같은 서브 클래스 화 된 블록 객체를 셀의 개념과 무관하게 열과 행으로 만듭니다. 그런 다음 블록 엔진을 사용하여이를 XSLS 파일로 변환하십시오.
과거 에는 OpenXML SDK를 성공적으로 사용 했지만 설명서를 읽고 처음부터 시작하지는 않습니다. 대신 제공된 문서 리플렉터 도구를 사용하여 Excel에서 원하는 내용을 정확하게 복사하여 저장 한 후 검사하십시오. 문서를 작성하는 데 필요한 C # 코드를 제공하여 배우고 수정할 수 있습니다.
답변
과거에 자주 사용했던 솔루션은 다음과 같습니다.
-
제목과 열의 기본 형식 및 제목 셀의 형식을 포함하여 모든 열 머리글을 포함하는 일반 Excel 문서 (일반적으로 xlsx 형식)를 템플릿으로 만듭니다.
-
해당 템플릿을 프로그램의 리소스에 포함시킵니다. 런타임시 첫 번째 단계는 템플릿을 새 파일로 추출하여 대상 폴더에 저장하는 것입니다.
-
Interop 또는 타사 라이브러리를 사용하여 새로 만든 xlsx에 데이터를 채 웁니다. 하드 코드 된 열 번호를 참조하지 말고 일부 메타 데이터 (예 : 열 헤더)를 사용하여 올바른 열을 식별하십시오.
장점 :
-
블록 접근과 같은 것이 이제 더 잘 작동합니다. 예를 들어, 열 교환 : 올바른 열이 헤더로 식별되므로 블록 코드에서 아무것도 변경할 필요가 없습니다.
-
열에 고유 한 서식이있는 경우 대부분의 서식은 템플릿을 조작하여 Excel에서 직접 수행 할 수 있습니다. 따라서 WYSIWYG 느낌과 함께 코드를 작성할 필요없이 Excel에서 사용할 수있는 형식 옵션을 자유롭게 사용할 수 있습니다.
단점 :
-
여전히 타사 lib 또는 Interop을 사용해야합니다. Interop이 느리다고 언급 했습니까?
-
템플릿에서 열 헤더가 변경되면 코드도 수정해야합니다 (그러나 예상 열이없는 경우 신호를 보내는 유효성 검사 루틴을 통해 쉽게 감지 할 수 있음)
-
동일한 열에서 다른 셀의 동적 서식이 필요한 경우 여전히 코드에서 처리해야합니다.
일반적인 힌트로, 어떤 접근 방식을 선택하든 레이아웃과 내용을 분리하고 선언적 솔루션을 사용하는 것이 유리합니다.
답변
고려해야 할 두 가지가 있습니다.
- 주어진 형식으로 파일을 작성하는 복잡성
- 파일 내용의 구조를 변경해야 할 때 코드가 손상 될 수 있습니다.
첫 번째에 관해서 :
생성해야하는 스프레드 시트에 서식 또는 수식이 포함되어 있지 않으면 실제 XLSX 대신 CSV 또는 탭으로 구분 된 파일을 생성하는 것이 매우 간단합니다. Excel은 기본적으로 많은 PC에서 이러한 파일을 엽니 다. 이것은 열과 행을 하드 코딩하는 데 도움이되지 않지만 Excel 개체 모델을 조작하는 추가 작업을 저장합니다.
서식이나 수식이 필요한 경우 특히 “하드 코딩되지 않은”스프레드 시트를 작성하는 경우 Excel 개체 모델로 작업하는 것이 합리적입니다. 다시 말해, 스프레드 시트에서 상대 수식과 범위 이름을 적절하게 사용하면 매직 넘버를 덜 하드 코딩 할 수 있습니다.
두 번째에 관해서 :
하드 코딩 된 행 및 열 참조를 사용하여 셀 단위로 작업하거나 배열 / 목록 모음 및 for
루프를 사용하여 셀 모집단을 일반화 할 수 있습니다 .