압축 된 일반 텍스트 파일을 부분적으로 추출하는 방법은 무엇입니까?


19

크기가 1.5GB 인 zip 파일이 있습니다.

그 내용은 말도 안되는 큰 일반 텍스트 파일 (60GB)이며 현재 디스크에 충분한 공간이 없어서 압축을 풀거나 압축을 풀고 싶습니다.

유스 케이스의 경우 내용의 일부를 검사 할 수 있으면 충분합니다.

따라서 파일을 스트림으로 압축 해제하고 파일 범위에 액세스하려고합니다 (일반 텍스트 파일의 머리와 꼬리를 통해 할 수있는 것처럼).

메모리 (예 : 32GB 마크에서 시작하여 최대 100kb 추출) 또는 줄 (일반 텍스트 줄 3700-3900)로 지정하십시오.

그것을 달성 할 수있는 방법이 있습니까?


1
불행히도 우편 번호 내의 개별 파일을 찾을 수는 없습니다. 따라서 모든 soloution에는 파일을 통해 원하는 지점까지 읽을 수 있습니다.
plugwash

5
@plugwash 질문을 이해하면서 목표는 zip 파일 (또는 압축 해제 파일)을 읽지 말고 전체 압축 해제 파일을 메모리 또는 디스크에 저장 하지 않는 것 입니다. 기본적으로 압축 해제 된 파일을 stream 으로 취급하십시오 .
ShreevatsaR

답변:


28

참고 gzip추출 할 수 있습니다 zip합니다 (적어도 첫 번째 항목 파일을 zip파일). 따라서 해당 아카이브에 거대한 파일이 하나만 있으면 다음을 수행 할 수 있습니다.

gunzip < file.zip | tail -n +3000 | head -n 20

예를 들어 3000 번째 라인부터 20 라인을 추출합니다.

또는:

gunzip < file.zip | tail -c +3000 | head -c 20

바이트와 ​​동일한 것 ( head을 지원 하는 구현 가정 -c).

아카이브에서 임의의 멤버의 경우 Unixy 방식으로 :

bsdtar xOf file.zip file-to-extract | tail... | head...

으로 head의 내장 ksh93(때와 같은 /opt/ast/bin전방에있다 $PATH), 당신은 할 수 있습니다 :

.... | head     -s 2999      -c 20
.... | head --skip=2999 --bytes=20

어쨌든 gzip/ bsdtar/ unzip는 항상 추출하려는 부분으로 이어지는 파일의 전체 섹션을 압축 해제하고 여기에서 버려야합니다. 그것은 압축 알고리즘의 작동 방식에 달려 있습니다.


경우 gzip, 윌 다른 "Z 인식"유틸리티 (처리 할 수 zcat, zless등) 또한 일을?
Ivanivan

@ivanivan은 기반으로하는 시스템에서 gzip(일반적으로 zless, zcat어떤 시스템에서는 여전히 .Z파일 을 읽지 않아도 되는 것은 아닙니다) 그렇습니다.
Stéphane Chazelas

14

unzip -p 및 dd를 사용하는 하나의 솔루션, 예를 들어 1000 블록 오프셋으로 10kb를 추출합니다.

$ unzip -p my.zip | dd ibs=1024 count=10 skip=1000 > /tmp/out

참고 : 나는 정말로 거대한 데이터로 이것을 시도하지 않았습니다 ...


일반적으로 단일 아카이브 내의 파일이 두 번 이상인 경우 unzip -l ARCHIVE아카이브 컨텐츠를 나열하고 unzip -p ARCHIVE PATH단일 오브젝트의 컨텐츠 PATH를 표준 출력 으로 추출하는 데 사용할 수 있습니다 .
David Foerster

3
일반적으로 ddcount 또는 skip이있는 파이프를 사용 하는 read()것은 최대 1024 바이트 의 많은 수를 수행하므로 신뢰할 수 없습니다 . 따라서 unzip크기가 1024의 배수 인 덩어리로 파이프에 쓰는 경우에만 제대로 작동합니다 .
Stéphane Chazelas

4

큰 zip 파일 생성을 제어 할 수 있다면 gzipand zless?

이를 통해 zless호출기 로 사용 하고 추출을 방해하지 않고 파일의 내용을 볼 수 있습니다.

압축 형식을 변경할 수 없으면 분명히 작동하지 않습니다. 그렇다면 나는 zless오히려 편리 하다고 생각 합니다.


1
난 아니야 외부 회사에서 제공 한 압축 파일을 다운로드하고 있습니다.
k0pernikus

3

파일의 특정 라인을 보려면 출력을 Unix 스트림 편집기 인 sed로 파이프하십시오 . 이를 통해 임의로 큰 데이터 스트림을 처리 할 수 ​​있으므로 데이터를 변경하는 데 사용할 수도 있습니다. 요청한대로 3700-3900 행을 보려면 다음을 실행하십시오.

unzip -p file.zip | sed -n 3700,3900p

7
sed -n 3700,3900p파일이 끝날 때까지 계속 읽습니다. 그것을 sed '3700,$!d;3900q'피하기 위해 사용 하는 것이 낫 거나 일반적으로 더 효율적입니다.tail -n +3700 | head -n 201
Stéphane Chazelas

3

파일의 시작 부분에서 압축 해제하는 것보다 더 효율적인 작업을 수행 할 수 있는지 궁금했습니다. 대답은 '아니오'인 것으로 보입니다. 그러나 일부 CPU (Skylake) zcat | tail에서는 CPU를 최대 클럭 속도로 올리지 않습니다. 아래를 참조하십시오. 사용자 지정 디코더는이 문제를 피하고 파이프 쓰기 시스템 호출을 저장할 수 있으며 ~ 10 % 더 빠를 수 있습니다. 전원 관리 설정을 조정하지 않으면 Skylake에서 ~ 60 % 더 빠릅니다.


skipbytes함수를 사용하여 사용자 정의 zlib로 할 수있는 최선의 방법 은 압축 해제 블록을 실제로 재구성하는 작업을 수행하지 않고 압축 블록의 기호를 구문 분석하여 끝까지 얻는 것입니다. 동일한 버퍼를 덮어 쓰고 파일에서 앞으로 이동하기 위해 zlib의 일반 디코드 기능을 호출하는 것보다 훨씬 빠를 수 있습니다 (아마도 2 배 이상). 그러나 나는 누군가가 그런 기능을 썼는지 모른다. (그리고 디코더가 특정 블록에서 다시 시작할 수 있도록 파일을 특별히 작성하지 않으면 실제로 작동하지 않는다고 생각합니다).

그 것 때문에 나는 그들을 디코딩하지 않고 공기를 빼다 블록을 건너 뛸 수있는 방법이 있었다 기대했다 훨씬 더 빨리. 허프만 트리는 각 블록의 시작 부분에 전송되므로 모든 블록의 시작 부분부터 디코딩 할 수 있습니다 (제 생각에는). 오, 나는 디코더 상태가 허프만 트리 이상이라고 생각합니다. 이것은 이전 32kiB의 디코딩 된 데이터이기도하며 기본적으로 블록 경계를 넘어서 재설정되거나 잊혀지지 않습니다. 동일한 바이트가 계속 반복해서 참조 될 수 있으므로 거대한 압축 파일에서 문자 그대로 한 번만 나타날 수 있습니다. (예를 들어, 로그 파일에서 호스트 이름은 압축 사전에서 항상 "핫"상태를 유지하며 모든 인스턴스는 첫 번째 이름이 아닌 이전 이름을 참조합니다).

zlib매뉴얼 에서는 압축 스트림을 그 시점 까지 검색하려면 Z_FULL_FLUSH호출 deflate할 때 사용해야한다고 말합니다 . 그것은 "압축 상태를 재설정"하므로, 그것 없이는 역 참조가 이전 블록으로 들어갈 수 있다고 생각합니다. 따라서 zip 파일이 때때로 전체 플러시 블록으로 작성되지 않는 한 (모든 1G 또는 압축에 무시할만한 영향을 줄 수있는 것처럼), 처음보다 원하는 지점까지 디코딩 작업을 더 많이 수행해야한다고 생각합니다. 생각. 나는 당신이 아마 어떤 블록의 시작에서 시작할 수 없을 것 같아요.


나머지 부분은 원하는 첫 번째 바이트가 포함 된 블록의 시작 부분을 찾고 거기에서 디코딩하는 것이 가능할 것이라고 생각하는 동안 작성되었습니다.

그러나 불행히도 Deflate 블록의 시작은 압축 블록의 길이를 나타내지 않습니다 . 압축 불가능한 데이터는 16 비트 크기의 바이트 단위 인 압축되지 않은 블록 형식으로 코딩 할 수 있지만 압축 블록은 그렇지 않습니다. RFC 1951은 형식을 매우 읽기 쉽게 설명합니다 . 동적 허프만 코딩을 사용하는 블록은 블록 앞쪽에 트리가 있으므로 (압축 해제 기는 스트림에서 탐색 할 필요가 없으므로) 컴프레서는 기록하기 전에 전체 (압축 된) 블록을 메모리에 보관해야합니다.

최대 역 참조 거리는 32kiB에 불과하므로 컴프레서는 압축되지 않은 데이터를 메모리에 많이 보관할 필요는 없지만 블록 크기를 제한하지는 않습니다. 블록의 길이는 여러 메가 바이트 일 수 있습니다. (이것은 디스크를 파싱하지 않고 현재 블록의 끝을 찾을 수 있다면 디스크로의 자기 탐색, 메모리로의 순차적 읽기 및 RAM에서 데이터 건너 뛰기에도 디스크 탐색이 가치가 있기에 충분합니다).

zlib은 가능한 한 블록을 만든다 : Marc Adler에 따르면 , zlib는 심볼 버퍼가 채워질 때만 새로운 블록을 시작한다. 기본 설정은 16,383 개의 심볼 (리터럴 또는 매치)이다


나는 seq(매우 중복적이고 따라서 큰 테스트는 아니지만) 출력을 pv < /tmp/seq1G.gz | gzip -d | tail -c $((1024*1024*1000)) | wc -cgzpping했지만 Skylake i7-6700k에서 3.9GHz의 DDR4-2666 RAM으로 ~ 62 MiB / s의 압축 데이터로 실행됩니다. 246MiB / s의 압축 해제 된 데이터 memcpy입니다. 캐시 크기에 비해 너무 큰 블록 크기의 경우 ~ 12GiB / s의 속도 와 비교할 때 급격한 변화 입니다.

(함께 energy_performance_preference기본으로 설정 balance_power하는 대신 balance_performance, 스카이 레이크의 내부 CPU 총재는 압축 된 데이터의 S / ~ 43 MiB 크기 만 2.7GHz의에서 실행하기로 결정합니다. 내가 사용 sudo sh -c 'for i in /sys/devices/system/cpu/cpufreq/policy[0-9]*/energy_performance_preference;do echo balance_performance > "$i";done'을 조정할 수 있습니다. 아마 빈번한 시스템 호출이 실제 CPU 바인딩처럼 보이지 않는다 전원 관리 장치로 작업하십시오.)

TL : DR : 디스크 zcat | tail -c매우 느린 경우가 아니면 고속 CPU에서도 CPU가 바인드 됩니다. gzip은 실행 한 CPU의 100 %를 사용하고 (에 따라 시계 당 1.81 개의 명령을 실행 perf) tail실행 한 CPU의 0.162를 사용했습니다 (0.58 IPC). 그렇지 않으면 시스템이 대부분 유휴 상태였습니다.

Meltdown 문제를 해결하기 위해 KPTI가 기본적 으로 활성화 된 Linux 4.14.11-1-ARCH를 사용하고 있으므로 모든 write시스템 호출 gzip이 이전보다 비쌉니다.


데 시크 내장에 unzip또는 zcat(여전히 정기적으로 사용하여 zlib디코딩 기능) 모든 파이프 쓰기를 절약 할 수 및 전체 클럭 속도로 작동하는 스카이 레이크 CPU를 얻을 것입니다. (일부 종류의로드에 대한이 다운 클럭킹은 Intel Skylake 이상에서 고유하며, CPU에서 수행하는 작업에 대한 더 많은 데이터가 있고 더 빠르게 증가 / 감소 할 수 있기 때문에 OS에서 CPU 주파수 의사 결정을 오프로드합니다. 일반적으로 좋지만 여기서는 더 보수적 인 주지사 설정으로 Skylake가 최고 속도로 올라가지 않습니다.

원하는 시작 바이트 위치에 도달 할 때까지 L2 캐시에 맞는 버퍼를 다시 작성하면 시스템 호출이 발생하지 않을 수 있습니다. 아마 10 % 일지 모르지만 난 여기서 숫자를 만들어 내고 있습니다. zlib캐시 풋 프린트의 크기와 모든 시스템 호출에서 TLB 플러시 (및 따라서 uop- 캐시 플러시)가 KPTI를 사용할 때 얼마나 많은지 알기 위해 세부적으로 프로파일 링하지 않았습니다 .


gzip 파일 형식에 탐색 색인을 추가하는 몇 가지 소프트웨어 프로젝트가 있습니다 . 검색 가능한 압축 파일을 생성 할 수있는 사람이 없다면 도움이되지 않지만 다른 독자들도 도움이 될 수 있습니다.

아마도 어느 쪽도이 프로젝트의 인덱스 때 만 작동하도록 설계하고 있기 때문에, 인덱스없이 공기를 빼다 스트림을 통해 생략하는 방법을 알고있는 디코드 기능이없는 것입니다 사용할 수 있습니다.


1

zip 파일을 파이썬 세션에서 zf = zipfile.ZipFile(filename, 'r', allowZip64=True)열 수 있습니다. 일단 열면 zip 아카이브 내부의 파일과 읽기 행 등을 일반 파일처럼 열 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.