xz(.xz) 스트림 분석기
.xz 파일은 프레임이 있는 형식이고, 그것이 gzip과의 결정적인 차이입니다. 모든 스트림은 12바이트 푸터로 끝나며 푸터의 백워드 크기가 인덱스의 위치를 가리킵니다. 인덱스에는 블록마다 레코드가 하나씩 들어 있고, 각 레코드는 그 블록의 언패디드 크기와 원본 크기를 담고 있습니다. 그래서 실제 원본 크기, 블록 개수, 탐색 지점이 모두 파일 끝의 수백 바이트만 읽으면 나옵니다. 4GB짜리 아카이브에서도 xz --list가 즉시 답하는 이유이고, 반대로 gzip -l이 .gz의 마지막 4바이트를 그대로 읽어 보여 주고 그게 전체를 뜻하기를 바라는 수밖에 없는 이유이기도 합니다. 이 페이지는 xz와 똑같이 파일 끝에서 거꾸로 거슬러 올라가며 같은 프레이밍을 읽고 전부 보여 줍니다. fd 37 7a 58 5a 00 매직, 검사 방식(None, CRC32, 기본값인 CRC64, SHA-256)을 담은 스트림 플래그와 그 두 바이트를 지키는 CRC32, 그리고 블록마다 헤더 크기, 헤더가 자신의 압축·원본 크기를 직접 선언했는지 여부, 저장된 검사값, 제대로 해석한 필터 체인입니다. LZMA2의 사전 크기는 단순한 숫자가 아니라 4KiB부터 4GiB까지 이어지는 6비트 부호이고, 그 앞에 x86, ARM, ARM64, PowerPC, IA-64, SPARC, ARM-Thumb, RISC-V용 BCJ 필터가 자신의 시작 오프셋과 함께 붙을 수 있습니다. --x86으로 만든 파일의 체인에 필터가 둘인 이유이며, 이 페이지는 그 체인을 xz에 그대로 다시 넘길 수 있는 형태로 적어 줍니다. 블록 다음에는 인덱스 레코드, 인덱스 자신의 CRC32, 푸터의 백워드 크기와 반복된 스트림 플래그, YZ 매직이 이어집니다. 압축은 전혀 풀지 않습니다. LZMA2는 구현하지 않았고 그럴 필요도 없다는 것이 이 도구의 요점이지만, 동시에 블록의 검사값은 검증한 값이 아니라 옮겨 적은 값이라는 뜻이기도 합니다. CRC64가 맞다고 증명하려면 결국 페이로드를 디코딩해야 하기 때문입니다. 반면 프레이밍 자체를 지키는 네 종류의 CRC32는 직접 다시 계산하며, 불일치가 있어도 파일을 거부하지 않고 그대로 보고합니다. 인덱스가 망가졌거나 푸터 플래그가 헤더와 어긋난 파일에서도 멀쩡한 부분은 전부 볼 수 있습니다. 블록 개수는 겉보기보다 중요합니다. 블록이 하나면 여러 코어로 나눠 풀 수도, 중간으로 탐색해 들어갈 수도 없습니다. xz -T0이 바꾸는 것이 바로 이 점인데, 입력을 사전 크기의 약 3배 단위로 자르기 때문에 그보다 작은 입력은 스레드를 아무리 많이 줘도 블록 하나로 남습니다. 한 파일에 여러 스트림이 이어 붙을 수도 있고 그 사이 패딩은 4의 배수인 0 바이트여야 하는데, 이 페이지는 스트림을 하나씩 나열하고 어느 스트림에도 속하지 않는 꼬리 바이트도 따로 지적합니다.
사용법
- .xz 또는 .tar.xz 파일을 상자에 놓으세요. 페이지 안에서만 읽으며 업로드도, 압축 해제도 하지 않습니다.
- 요약부터 보세요. 스트림 수, 블록 수, 인덱스에서 가져온 실제 원본 크기, 압축비, 그리고 이 파일이 쓰는 검사 방식이 나옵니다.
- 스트림을 펼치면 헤더, 블록 표, 인덱스가 보입니다. 필터 열은 xz에 그대로 넘길 수 있는 형태라 --x86 --lzma2=dict=8MiB가 곧 그 블록을 만든 체인입니다.
- 병렬 압축 해제나 부분 읽기를 계획하기 전에 블록 수를 확인하세요. 블록이 하나면 스레드를 몇 개 주든 코어 하나로 처리되고 탐색도 불가능합니다.
- 프레이밍 타일이 불일치라면 빨간 배지를 찾아보세요. 스트림 헤더, 블록 헤더, 인덱스, 푸터가 각각 자기 CRC32를 갖고 있고 푸터는 스트림 플래그를 한 번 더 반복합니다.
자주 묻는 질문
- 압축을 풀지 않고 어떻게 원본 크기를 알 수 있나요?
- .xz 형식이 그 숫자를 파일에 적어 두기 때문입니다. 스트림 끝에는 블록마다 언패디드 크기와 원본 크기를 나열한 인덱스가 있고, 푸터의 백워드 크기가 인덱스가 얼마나 앞에서 시작하는지 알려 줍니다. 읽는 쪽은 마지막 12바이트로 건너뛰고, 인덱스로 이동해 레코드를 더하면 끝입니다. xz --list가 하는 일이 그것이고 이 페이지가 하는 일도 같습니다. .xz를 중간부터 읽을 수 있는 이유이기도 합니다. 특정 원본 오프셋이 어느 블록에 있는지 인덱스가 알려 주니까요. gzip에는 이에 해당하는 구조가 없습니다. ISIZE는 파일의 마지막 4바이트에 있고 마지막 멤버만 설명하며 2^32로 나눈 나머지라, 멤버가 여럿이거나 4GB가 넘는 .gz는 프레이밍만으로 크기를 말할 수 없습니다.
- -T0으로 압축했는데 왜 블록이 하나뿐인가요?
- 스레드 압축은 입력을 사전 크기의 약 3배 단위로 자르는데, 기본 프리셋 6의 사전은 8MiB라 약 24MiB보다 작은 입력은 절대 둘로 나뉘지 않습니다. -T0은 코어 수만큼 스레드를 쓰라는 요청일 뿐, 한 덩어리에 들어가는 입력에서 두 번째 블록을 만들어 내지는 못합니다. 병렬 압축 해제나 탐색이 목적이라 블록 자체가 필요하다면 --block-size나 --block-list로 명시하세요. 대가는 압축률입니다. 블록마다 사전이 비어 있는 상태에서 시작하므로 경계 너머의 일치는 찾지 못합니다.
- 검사 방식은 무엇을 골라야 하고 비용은 얼마인가요?
- 스트림 플래그가 None, CRC32, CRC64, SHA-256 넷 중 하나를 지정하고, 블록마다 각각 0, 4, 8, 32바이트를 뒤에 붙입니다. 기본값인 CRC64가 거의 언제나 정답입니다. 블록당 몇 바이트로 저장 장치와 전송이 실제로 만들어 내는 우발적 손상을 잡아냅니다. SHA-256은 블록당 32바이트에 CPU도 훨씬 많이 쓰는데, 무엇을 사 주지 않는지는 분명히 해 두는 편이 좋습니다. 다이제스트가 파일 안에 있으므로 페이로드를 고칠 수 있는 사람은 다이제스트도 고칠 수 있습니다. 즉 사고에 대한 탐지이지 공격자에 대한 방어가 아니며, 그 용도에는 파일 전체에 대한 서명이 필요합니다. --check=none은 4~8바이트를 아끼는 대신 데이터가 상했다고 알려 줄 유일한 수단을 없앱니다. 페이로드가 자체 체크섬을 갖고 있을 때 정도가 정당화될 수 있습니다.
- 언패디드 크기, 전체 크기, 압축 크기는 어떻게 다른가요?
- 같은 블록을 세 방향에서 본 값입니다. 압축 크기는 LZMA2가 뱉어낸 바이트만 셉니다. 인덱스에 실제로 저장되는 언패디드 크기는 블록 헤더 + 그 압축 데이터 + 검사값이며 패딩은 세지 않습니다. 전체 크기는 언패디드 크기를 4의 배수로 올림한 값인데, 다음 블록이 정렬된 위치에서 시작하도록 블록마다 0 바이트를 채우기 때문입니다. 둘을 빼면 0~3바이트의 패딩이 나옵니다. 이 페이지는 압축 데이터 크기와 패딩을 따로 보여 주고, 헤더가 자기 크기를 선언한 경우에는 두 값을 블록 헤더와 교차 검증합니다. 크기 필드 열의 c와 u가 뜻하는 것이 바로 그 선언입니다.
- 이 페이지는 불일치라는데 xz -t는 그냥 데이터가 손상됐다고만 합니다. 어느 쪽이 맞나요?
- 깊이가 다를 뿐 둘 다 맞습니다. xz -t는 페이로드 전체를 디코딩하고 블록마다 검사값을 확인하므로 어디의 손상이든 잡아내지만, 첫 오류에서 멈추고 무엇이 잘못됐든 같은 문장으로 보고합니다. 이 페이지는 페이로드를 전혀 디코딩하지 않으므로 압축 데이터 내부의 손상은 아예 보지 못합니다. 대신 프레이밍의 CRC32를 각각 따로 다시 계산하므로 어느 구조가 망가졌는지 짚어 줍니다. 스트림 헤더인지, 어느 블록의 헤더인지, 인덱스인지, 푸터인지 말이죠. 헤더의 스트림 플래그와 푸터의 사본을 비교하기도 하는데, 크기 기반 점검으로는 보이지 않는 이 불일치는 진짜 손상 신호입니다. 손상 위치는 이 페이지로 좁히고, 데이터를 쓸 수 있는지는 xz -t로 판단하세요.
- .tar.xz 안의 파일 목록도 볼 수 있나요?
- 볼 수 없고, 압축을 풀지 않는 한 어떤 도구도 볼 수 없습니다. 파일 이름, 크기, 권한이 들어 있는 tar 아카이브 자체가 페이로드이고, 그 페이로드는 LZMA2로 압축된 불투명한 바이트 덩어리입니다. 프레이밍에서 알 수 있는 것은 풀었을 때 그 tar가 얼마나 커지는지(시작하기 전에 들어갈 자리가 있는지 알 수 있습니다), 블록이 몇 개인지(추출에 여러 코어를 쓸 수 있는지 알 수 있습니다), 그리고 컨테이너가 온전한지입니다. 원본 크기가 512의 배수로 딱 떨어진다면 실제로 tar일 가능성이 높습니다. tar는 멤버마다, 그리고 아카이브 전체를 그 블록 크기로 채우기 때문입니다.
- 필터 체인에 적힌 사전 크기는 무엇을 알려 주나요?
- 압축기가 반복을 찾으러 얼마나 뒤까지 볼 수 있었는지, 따라서 압축을 푸는 쪽이 메모리를 대략 얼마나 쓰게 될지를 알려 줍니다. 디코더는 사전 크기만 한 버퍼를 잡으므로 -9(64MiB)로 만든 .xz를 열려면 65MB 남짓이 필요하고, 그만한 메모리가 없는 기기도 있습니다. 노트북에서는 잘 열리는 파일이 임베디드 기기나 CI에서 압축 해제에 실패하는 흔한 원인입니다. LZMA2는 이 값을 6비트 부호로 저장합니다. 0번 비트가 가수 2 또는 3을 고르고 나머지가 지수라, 사다리는 4KiB, 6KiB, 8KiB, 12KiB 식으로 3GiB까지 올라가며 값 40 하나만 4GiB에서 1을 뺀 크기로 예약돼 있습니다. 단순한 정수로 읽으면 기본값인 8MiB 사전이 22로 보일 겁니다.
관련 도구
TAR 아카이브 검사기
.tar, .tar.gz, .tgz 파일을 풀지 않고 내부 항목을 전부 봅니다. 권한, 소유자, 크기, 시각, 링크 대상까지 표시합니다.
NumPy .npy / .npz 검사기
.npy·.npz 헤더를 브라우저에서 읽습니다. dtype, shape, 바이트 순서, 필드 배치와 값 미리보기까지. NumPy 설치도 업로드도 필요 없습니다.
gzip(.gz) 구조 분석기
.gz 헤더를 필드 단위로 읽고 모든 멤버를 훑은 뒤, 브라우저에서 CRC32와 실제 크기를 다시 계산해 트레일러를 검증합니다.
MIME 타입 조회
확장자로 MIME 타입을 찾거나 그 반대로 조회. 각 타입의 용도 설명.
CIDR 통합기 (IP 범위 병합 · 최소 블록 분해)
어수선한 IPv4/IPv6 주소·CIDR·범위 목록을 받아 최소 개수의 CIDR 블록으로 정리합니다.
이메일 헤더 분석
원본 이메일 헤더 붙여넣기 → Received 홉 순서대로·홉간 지연·SPF/DKIM/DMARC 결과 확인.