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

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

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

그 내용은 터무니없이 큰 일반 텍스트 파일(60GB)이고, 현재 디스크에 모든 것을 추출할 만큼 충분한 공간이 없으며, 추출했다고 하더라도 모두 추출하고 싶지 않습니다.

내 사용 사례의 경우 일부를 확인할 수 있으면 충분합니다.

그래서 파일의 압축을 스트림으로 풀고 파일 범위에 액세스하고 싶습니다(일반 텍스트 파일의 헤드와 테일을 통해 액세스할 수 있는 것처럼).

메모리(예: 32GB 표시에서 시작하여 최대 100kb 추출) 또는 줄(일반 텍스트 줄 3700-3900 제공)을 사용합니다.

이것을 달성할 수 있는 방법이 있나요?

답변1

파일(최소한 파일의 첫 번째 항목 ) gzip을 추출할 수 있습니다 . 따라서 해당 아카이브에 큰 파일이 하나만 있는 경우 다음을 수행할 수 있습니다.zipzip

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파일의 전체 섹션을 항상 압축을 풀고 여기에서 삭제해야 한다는 점에 유의하세요. 압축 알고리즘의 작동 방식에 따라 다릅니다.bsdtarunzip

답변2

unzip -p 및 dd를 사용하는 솔루션(예: 10kb 및 1000 블록 오프셋 추출):

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

참고: 매우 큰 데이터를 사용하려는 것은 아닙니다...

답변3

큰 zip 파일 생성을 제어할 수 있다면 gzip및 의 조합 사용을 고려해 보는 것은 어떨까요 zless?

이렇게 하면 해당 파일을 호출기로 사용할 수 zless있으며 파일을 추출하지 않고도 파일 내용을 볼 수 있습니다.

압축 형식을 변경할 수 없으면 분명히 작동하지 않습니다. 그렇다면 zless더 편리한 것 같아요.

답변4

파일의 처음부터 이 지점까지 압축을 푸는 것보다 더 효율적인 일을 할 수 있지 않을까 하는 생각이 들었습니다. 대답은 '아니요'인 것 같습니다. 그러나 일부 CPU(Skylake)에서는 zcat | tailCPU가 최대 클럭 속도로 향상되지 않습니다. 아래를 참조하세요. 사용자 지정 디코더는 문제를 방지하고 파이프라인 쓰기 시스템 호출을 저장할 수 있으며 속도가 10% 더 빠를 수 있습니다. (또는 전원 관리 설정을 조정하지 않으면 Skylake에서 60% 더 빠릅니다.)


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

Deflate 청크를 디코딩하지 않고 건너뛸 수 있는 방법이 있었으면 좋겠습니다.많은서둘러요. 허프만 트리는 각 블록의 시작 부분에 전송되므로 모든 블록의 시작 부분부터 디코딩할 수 있습니다. 아, 내 생각에 디코더 상태는 허프만 트리뿐만 아니라 이전 32kiB의 디코딩된 데이터이기도 하며 기본적으로 블록 경계를 넘어 재설정/잊혀지지 않습니다. 동일한 바이트는 계속해서 반복적으로 참조될 수 있으므로 대용량 압축 파일에서는 한 번만 나타날 수 있습니다. (예를 들어, 로그 파일에서 호스트 이름은 압축 사전에서 항상 "핫" 상태로 유지될 수 있으며 호스트 이름의 각 인스턴스는 첫 번째 인스턴스가 아닌 이전 인스턴스를 참조합니다.)

zlib수동압축된 스트림을 이 지점까지 검색할 수 있도록 하려면 Z_FULL_FLUSH호출할 때 이 속성을 사용해야 함을 나타냅니다. deflate"압축 상태를 재설정"하므로 이것이 없으면 역방향 참조가 이전 블록으로 들어갈 수 있다고 생각합니다. 따라서 zip 파일이 가끔 전체 플러시 청크(예: 각각 1G 또는 압축에 미치는 영향을 무시할 수 있는 다른 것)로 작성되지 않는 한 원하는 지점까지 더 많은 디코딩을 수행해야 한다고 생각합니다. 원래 생각했어요. 어떤 블록의 시작 부분부터 시작하지 못할 수도 있습니다.


나머지는 필요한 첫 번째 바이트가 포함된 블록의 시작 부분을 찾아 거기에서 디코딩할 수 있다고 생각될 때 작성됩니다.

그러나 불행하게도 Deflate 블록의 시작은 그것이 얼마나 오래 걸리는지 나타내지 않습니다., 압축된 블록의 경우. 압축할 수 없는 데이터는 이전 16비트 바이트 크기를 갖는 압축되지 않은 블록 유형을 사용하여 인코딩할 수 있지만 압축된 블록은 다음을 수행하지 않습니다.RFC 1951에는 형식에 대한 매우 읽기 쉬운 설명이 있습니다.. 동적 허프만 코딩을 사용하는 블록은 블록 앞에 트리가 있으므로(압축 해제기가 스트림을 볼 필요가 없음) 압축기는 쓰기 전에 전체(압축된) 블록을 메모리에 유지해야 합니다.

최대 역방향 참조 거리는 32kiB에 불과하므로 압축기는 압축되지 않은 데이터를 메모리에 많이 보관할 필요가 없지만 이로 인해 블록 크기가 제한되지는 않습니다. 블록의 길이는 수 메가바이트일 수 있습니다. (이는 현재 블록의 끝을 구문 분석하지 않고 찾을 수 있는 경우 메모리를 순차적으로 읽고 RAM의 데이터를 건너뛰는 것보다 자기 드라이브에서도 디스크 탐색을 수행할 가치가 있을 만큼 충분히 큽니다.)

zlib는 가능한 한 오랫동안 블록을 만듭니다. 마크 애들러에 따르면, zlib는 기호 버퍼가 가득 찰 때만 새 블록을 시작합니다. 기본값은 16,383 기호(리터럴 또는 일치)입니다.


출력을 gzip으로 압축했지만 seq(매우 중복되므로 좋은 테스트가 아닐 수 있음) pv < /tmp/seq1G.gz | gzip -d | tail -c $((1024*1024*1000)) | wc -cDDR4-2666 RAM 데이터가 실행되는 3.9GHz의 Skylake i7-6700k에서 약 62MiB/s로만 압축되었습니다. 데이터 압축 해제 속도는 246MiB/s로, memcpy블록 크기가 너무 커서 캐시에 맞지 않기 때문에 약 12GiB/s의 속도에서 무시할 수 있는 변화입니다.

( Skylake의 내부 CPU 거버너는 대신 energy_performance_preference기본값으로 설정할 때 약 43MiB/s의 압축 데이터인 2.7GHz에서만 실행하기로 결정했습니다 . 자주 조정합니다. 이렇게 빈번한 시스템 호출이 실제 CPU 제한 작업처럼 보이지 않을 수도 있습니다. 전원 관리 장치).balance_powerbalance_performancesudo sh -c 'for i in /sys/devices/system/cpu/cpufreq/policy[0-9]*/energy_performance_preference;do echo balance_performance > "$i";done'

번역: 박사:zcat | tail -c당신이 가지고 있지 않는 한 빠른 CPU에서도 CPU에 바인딩되어 있습니다.매우디스크가 느립니다. gzip은 CPU의 100%(참조에 따르면 클럭당 1.81 명령 perf) 를 사용했으며 tail0.162 CPU(0.58 IPC)를 사용했습니다. 그렇지 않으면 시스템은 대부분의 시간 동안 유휴 상태로 유지됩니다.

저는 Linux 4.14.11-1-ARCH를 사용하고 있습니다.KPTI는 기본적으로 활성화되어 있습니다.Meltdown 문제를 수정하여 모든 writesyscall이 gzip이전보다 더 비싸지도록 합니다. :/


unzip또는 에 대한 검색 기능 내장 zcat(그러나 여전히 일반 zlib디코딩 기능을 사용함)이러한 파이프라인 쓰기를 모두 저장하고 Skylake CPU가 최대 클럭 속도로 실행될 수 있도록 합니다. (특정 로드에 대한 이러한 다운클러킹은 Intel Skylake 이상에 고유하며, CPU가 수행하는 작업에 대한 더 많은 데이터가 있고 주파수를 더 빠르게 업/다운할 수 있기 때문에 운영 체제에서 CPU 주파수 결정을 오프로드했습니다. 이는 일반적으로 좋지만 여기서는 다음과 같습니다. 보다 보수적인 거버너 설정에서는 Skylake가 최대 속도로 실행되지 않습니다.

시스템 호출 없이 원하는 시작 바이트 위치에 도달할 때까지 L2 캐시에 맞는 버퍼를 다시 작성하면 아마도 최소한 몇 %의 차이가 생길 것입니다. 어쩌면 10%일 수도 있지만 여기서는 단지 숫자를 만들어낸 것뿐입니다. zlibKPTI가 활성화된 경우 캐시 집약적 방식과 모든 시스템 호출의 TLB 플러시(및 uop 캐시 플러시)가 얼마나 영향을 받는지 자세히 분석 하지 않았습니다 .


gzip 파일 형식에 검색 색인을 추가하는 일부 소프트웨어 프로젝트가 있습니다.. 다른 사람이 귀하를 위해 찾을 수 있는 zip 파일을 생성하도록 할 수 없다면 이는 도움이 되지 않지만 미래의 다른 독자들이 도움을 받을 수 있습니다.

아마도 이들 프로젝트 중 어느 프로젝트도 색인 없이 Deflate 스트림을 건너뛰는 방법을 알 수 있는 디코딩 기능이 없을 것입니다. 왜냐하면 색인 없이만 작동하도록 설계되었기 때문입니다.쓸 수 있는.

관련 정보