--- description: globs: alwaysApply: false --- # XLSX 파일 처리 오류 방지 및 디버깅 ## **문제 상황** - SheetJS로 읽은 XLSX 파일에서 `workbook.Sheets`가 undefined이거나 올바른 객체가 아닌 경우 - "파일에 유효한 시트가 없습니다" 오류가 발생하는 경우 - 한글 파일명이나 특수 문자가 포함된 XLSX 파일 처리 시 문제 ## **필수 검증 단계** ### **1. 워크북 객체 검증** ```typescript // ✅ DO: 워크북 구조 전체 디버깅 console.log("🔍 워크북 구조 분석:"); console.log("- workbook 존재:", !!workbook); console.log("- workbook 전체 키:", Object.keys(workbook)); console.log("- workbook.Sheets 존재:", !!workbook.Sheets); console.log("- workbook.Sheets 타입:", typeof workbook.Sheets); // ❌ DON'T: 단순한 truthy 체크만 하지 말 것 if (workbook.Sheets) { ... } ``` ### **2. SheetJS 읽기 옵션 최적화** ```typescript // ✅ DO: 안전한 SheetJS 옵션 사용 workbook = XLSX.read(arrayBuffer, { type: "array", cellText: false, // 텍스트 셀 비활성화 cellDates: true, // 날짜 형식 유지 sheetStubs: false, // 빈 셀 스텁 비활성화 codepage: 65001, // UTF-8 설정 bookProps: false, // 워크북 속성 비활성화 bookSheets: true, // 시트 정보만 활성화 raw: false, // 원시 값 비활성화 WTF: false // 엄격 모드 비활성화 }); // ❌ DON'T: 기본 옵션만 사용하지 말 것 workbook = XLSX.read(arrayBuffer); ``` ### **3. 단계별 오류 처리** ```typescript // ✅ DO: 각 단계별 구체적 오류 메시지 if (!workbook) { throw new Error("파일에서 워크북을 생성할 수 없습니다."); } if (!workbook.Sheets || typeof workbook.Sheets !== "object") { console.error("❌ Sheets 속성 오류:", { exists: !!workbook.Sheets, type: typeof workbook.Sheets, value: workbook.Sheets }); throw new Error("파일에 유효한 시트가 없습니다."); } // ❌ DON'T: 일반적인 오류 메시지만 사용하지 말 것 throw new Error("파일 처리 실패"); ``` ### **4. 개별 시트 검증** ```typescript // ✅ DO: 각 시트의 구조 확인 workbook.SheetNames.forEach((sheetName, index) => { const sheet = workbook.Sheets[sheetName]; console.log(`- 시트 [${index}] "${sheetName}":`, { exists: !!sheet, type: typeof sheet, keys: sheet ? Object.keys(sheet).slice(0, 5) : [] }); }); // ❌ DON'T: 시트 존재만 확인하고 내용 검증 생략하지 말 것 const hasSheets = workbook.SheetNames.length > 0; ``` ## **한글 파일 처리 특수 사항** ### **1. 인코딩 처리** ```typescript // ✅ DO: UTF-8 실패 시 CP949로 재시도 (XLS의 경우) try { workbook = XLSX.read(arrayBuffer, { codepage: 65001 }); // UTF-8 } catch (error) { if (isXLS) { workbook = XLSX.read(arrayBuffer, { codepage: 949 }); // CP949 } } ``` ### **2. 파일명 및 시트명 검증** ```typescript // ✅ DO: 한글 시트명 안전 처리 const safeSheetName = sheetName || `Sheet${index + 1}`; console.log(`🔍 처리 중인 시트: "${safeSheetName}"`); // ❌ DON'T: 시트명을 검증 없이 직접 사용하지 말 것 console.log(`처리 중: ${sheetName}`); ``` ## **성능 최적화** ### **1. 메모리 효율적 처리** ```typescript // ✅ DO: 큰 파일 처리 시 메모리 체크 if (arrayBuffer.byteLength > 50 * 1024 * 1024) { // 50MB console.warn("⚠️ 대용량 파일 처리 중..."); } // ✅ DO: 변환 결과 검증 if (!xlsxBuffer || xlsxBuffer.byteLength === 0) { throw new Error("XLSX 변환 결과가 비어있습니다."); } ``` ## **테스트 고려사항** - 한글 파일명이 포함된 XLSX 파일 테스트 - 빈 시트가 포함된 파일 테스트 - 손상된 XLSX 파일 테스트 - 대용량 파일 처리 테스트 - 특수 문자가 포함된 시트명 테스트 참고: [xls_processing.mdc](mdc:.cursor/rules/xls_processing.mdc)와 연계하여 사용