본문으로 건너뛰기

.xlsb의 잘린 행 복구

문서 목록으로

셀 리더가 일부 행을 실제보다 짧게 보고해 값이 있는 셀이 조용히 사라지는 결함과, 그것을 되찾는 설계입니다.

.xlsb의 정의된 이름 §2가 이 결함을 기록하고 §7에서 범위 밖으로 두었습니다. 그 판단의 근거가 깨졌습니다 — 「이름 사각형 안쪽에는 차이가 없다」고 적었는데, 지금 데이터에서는 안쪽에서 발생합니다.


1. 무엇이 잘못되었는가 — 엑셀을 기준으로 판정

<워크북>.xlsbWorldNpc 시트, 엑셀 317행입니다.

누가무엇이라고 하는가
파일의 레코드col 70 : BrtCellRk 0x02A62B1E11111111
행 헤더colspan (0, 70) — 71개 컬럼을 선언
엑셀 자신 (COM)Cells(317, 71).Value2 = 11111111
셀 리더RowFieldCount = 66, GetValue(70) = 빈 값

바로 위 315행은 구조가 같은데 71을 제대로 보고합니다.

RowNumber=315 RowFieldCount=71 col70 = 11111111
RowNumber=317 RowFieldCount=66 col70 = (사라짐)

리더의 결함입니다. 파일에도 있고 엑셀도 읽는 값을, 리더만 내주지 않습니다. GetValue가 예외를 던지지도 않아 호출하는 쪽에서 구별할 수 없습니다.

라이브러리 버전을 올려도 달라지지 않습니다 — 쓰고 있는 것이 최신입니다.

무엇이 방아쇠인지는 아직 모릅니다

.xlsx에서는 나타나지 않고, 규칙이 잡히지 않습니다.

가설측정
빈 행 다음 행이 잘린다부분적으로만 맞습니다 — 빈 행 다음 행의 45%가 짧고, 그 밖의 행도 9.5%가 짧습니다
특정 레코드 종류에서 멈춘다잘린 행과 안 잘린 다음 행이 66~70번 컬럼에서 레코드 종류가 같습니다
공유 문자열 인덱스가 범위 밖아닙니다 — 둘 다 범위 안이고 같은 인덱스입니다
행 헤더의 colspan이 좁다아닙니다 — 잘린 행도 (0, 70)을 선언합니다

방아쇠를 모르는 채로도 복구는 가능합니다. 무엇이 사라졌는지는 파일이 말해주기 때문입니다.

2. 규모 — 실측

짧은 행 자체는 정상입니다. 끝의 빈 셀은 저장되지 않으므로, 150만 행 중 97,552개(6.4%)가 짧고 .xlsx에도 있습니다. 그래서 RowFieldCount < FieldCount는 결함의 신호가 아닙니다.

값을 실제로 잃는 행만 세려면 파일의 레코드와 대조해야 합니다. .xlsb 21개 전량입니다.

무엇
대조한 행718,764
값을 잃은 행2,226 (0.31%)
잃은 셀 (하한)126,468
워크북잃은 행
중국 데이터 취합.xlsb1,545
<워크북>.xlsb523
<워크북>.xlsb28
<워크북>.xlsb24
나머지 11개각 25개 이하

0.31%가 작아 보이는 것이 이 결함의 성질입니다. WorldNpc에서 잃은 것은 4행뿐인데, 그 4행이 :required 컬럼을 비게 만들어 79,181행짜리 테이블 전체가 변환 대상에서 빠졌습니다. 잃은 양이 아니라 잃었다는 사실이 비용입니다.

3. 설계 — 사라진 행만 파일에서 되읽기

리더를 대체하지 않습니다. 718,764행 중 2,226행이므로, 리더가 제대로 읽은 99.7%는 그대로 쓰고 잘린 행만 파일에서 다시 읽습니다.

단계무엇
1.xlsb를 열 때 시트마다 행별 마지막 값 컬럼을 레코드에서 훑습니다. 값 파싱 없이 컬럼 번호만 세므로 한 번의 순차 읽기입니다
2행을 읽을 때 RowFieldCount가 그보다 작으면 그 행의 셀을 레코드에서 디코드합니다
3되찾은 셀을 리더가 준 행 뒤에 이어 붙입니다
4복구한 행 수를 실행 요약에 보고합니다 — 조용히 고치면 결함이 있다는 사실이 사라집니다

왜 「전체를 우리가 읽기」가 아닌가

셀 하나의 텍스트를 만드는 데는 값 말고도 숫자 서식·날짜 체계·공유 문자열의 서식 실행이 필요하고, 그것을 다시 쓰면 리더와 미세하게 다른 텍스트를 냅니다. 그러면 골든이 전부 움직이고, 그 diff가 결함 때문인지 재구현 때문인지 가릴 수 없게 됩니다.

0.31%만 되읽으면 나머지는 한 바이트도 움직이지 않습니다.

디코드해야 하는 레코드

레코드무엇
BrtCellBlank값 없음. 자리만 차지합니다
BrtCellRk압축된 수 — 정수/실수, ×100 플래그
BrtCellReal배정밀도
BrtCellBool · BrtCellError참/거짓, 수식 오류
BrtCellSt인라인 문자열
BrtCellIsst공유 문자열 — xl/sharedStrings.bin 참조
BrtFmlaString · BrtFmlaNum · BrtFmlaBool · BrtFmlaError수식의 캐시된 결과. 수식 자체는 읽지 않습니다

서식은 읽지 않습니다. 이 레이아웃들이 읽는 것은 셀의 값이고, 날짜로 서식된 수가 복구 대상에 나타나면 그때 판단합니다 — 지금 나타나지 않는 것을 미리 만들지 않습니다.

4. 게이트

무엇어떻게
픽스처잘린 행을 가진 .xlsb 하나. 이 결함은 우리가 만들 수 없으므로, 실제로 재현되는 워크북에서 해당 시트만 뽑아 최소 크기로 만듭니다
대조복구 뒤의 셀 값이 엑셀이 내는 값과 같을 것. 리더가 준 값이 아니라 엑셀이 기준입니다
리더 골든xlsx-reader.tsv가 움직입니다 — 복구된 셀만큼 cellschars가 늘어납니다. 그 증가분이 곧 이 작업의 결과이므로 diff를 리뷰합니다
보고복구한 행이 0이 아닌 실행에서 요약에 그 수가 나올 것

5. 함께 정정되는 것

무엇어디
「이름 사각형 안쪽에는 영향이 없다」.xlsb의 정의된 이름 §2·§7
WorldNpc·OceanNpcTemplate을 대상에서 뺀 것recipe-all.jsonc. 복구되면 그 제외가 없어집니다
WorldNpc.regionBitFlag의 required 위반 4건시트 오류 보고에 시트 문제로 올라가 있지 않은지 확인

6. 상류에 보고할 것

최소 재현이 있습니다 — <워크북>.xlsbWorldNpc 시트 317행. 파일에 BrtCellRk가 있고 행 헤더가 colspan (0,70)을 선언하는데 RowFieldCount가 66입니다. 방아쇠를 모르므로 재현 파일과 함께 넘깁니다.