.NET GZipStream
은 파일의 첫 번째 레코드 인 일반 텍스트의 첫 번째 548 바이트의 압축을 풉니 다. 7Zip은 전체 파일을 1.2GB 출력 파일로 추출하지만 레코드 구분 기호가없는 일반 텍스트 (약 130 만 라인 상당)이며 7Zip에서 파일을 테스트 할 때 1,441 바이트를보고합니다.
몇 가지 사항을 확인하고 직접 압축을 풀 수있는 압축 라이브러리를 찾을 수 없습니다.
파일에서 약 캐스팅 한 후 1,441 바이트가 일반적으로 압축 된 데이터에 추가 된 8 바이트 바닥 글 레코드의 일부인 gzip 파일의 마지막 4 바이트 인 ISIZE
의 값이라는 것을 알았습니다 덩어리.
큰 숫자의 .gz 파일이 함께 연결되어있는 것으로 나타났습니다. 그게 엉덩이에 완전히 고통 스럽지만, 당신이 이것을 접근 할 수있는 몇 가지 방법이 있습니다.
첫 번째는 gzip 헤더 서명 바이트 : 0x1F
및 0x8B
에 대한 압축 파일을 스캔하는 것입니다. 이 파일을 찾으면 (일반적으로) 스트림에 각 .gz 파일의 시작 부분이 있습니다. 파일의 오프셋 목록을 작성한 다음 파일의 각 청크를 추출하고 압축을 풀 수 있습니다.
또 다른 옵션은 입력 스트림에서 소비 한 바이트 수를보고하는 라이브러리를 사용하는 것입니다. 거의 모든 압축 해제 기가 일종의 버퍼링을 사용하기 때문에 입력 스트림이 소비 된 바이트 수보다 훨씬 더 많이 이동하므로 직접 추측하기가 어렵습니다. 그러나 DotNetZip
스트림은 실제 사용 된 입력 바이트를 제공 할 것이며,이 바이트를 사용하여 다음 시작 위치를 파악할 수 있습니다. 이렇게하면 파일을 스트림으로 처리하고 각 파일을 개별적으로 추출 할 수 있습니다.
어느 쪽이든 빠르지는 않습니다.
다음은 DotNetZip
라이브러리를 사용하여, 두 번째 옵션에 대한 방법입니다 :
public static IEnumerable<byte[]> UnpackCompositeFile(string filename)
{
using (var fstream = File.OpenRead(filename))
{
long offset = 0;
while (offset < fstream.Length)
{
fstream.Position = p;
byte[] bytes = null;
using (var ms = new MemoryStream())
using (var unpack = new Ionic.Zlib.GZipStream(fstream, Ionic.Zlib.CompressionMode.Decompress, true))
{
unpack.CopyTo(ms);
bytes = ms.ToArray();
// Total compressed bytes read, plus 10 for GZip header, plus 8 for GZip footer
offset += unpack.TotalIn + 18;
}
yield return bytes;
}
}
}
그것은 빠른 추한 아니다 (전체 파일의 압축을 나에게 약 48 초 걸렸습니다)하지만이 일 것으로 보인다. 각 byte[]
출력은 스트림의 단일 압축 파일을 나타냅니다. 이것들은 System.Text.Encoding.UTF8.GetString(...)
으로 문자열로 바꿀 수 있고 그 다음 의미를 추출하기 위해 구문 분석 될 수 있습니다.
파일의 마지막 항목은 다음과 같습니다
WARC/1.0
WARC-Type: metadata
WARC-Target-URI: https://zverek-shop.ru/dljasobak/ruletka_sobaki/ruletka-tros_standard_5_m_dlya_sobak_do_20_kg
WARC-Date: 2017-11-25T14:16:01Z
WARC-Record-ID: <urn:uuid:e19ef645-b057-4305-819f-7be2687c3f19>
WARC-Refers-To: <urn:uuid:df5de410-d4af-45ce-b545-c699e535765f>
Content-Type: application/json
Content-Length: 1075
{"Container":{"Filename":"CC-MAIN-20171117170336-20171117190336-00002.warc.gz","Compressed":true,"Offset":"904209205","Gzip-Metadata":{"Inflated-Length":"463","Footer-Length":"8","Inflated-CRC":"1610542914","Deflate-Length":"335","Header-Length":"10"}},"Envelope":{"Format":"WARC","WARC-Header-Length":"438","Actual-Content-Length":"21","WARC-Header-Metadata":{"WARC-Target-URI":"https://zverek-shop.ru/dljasobak/ruletka_sobaki/ruletka-tros_standard_5_m_dlya_sobak_do_20_kg","WARC-Warcinfo-ID":"<urn:uuid:283e4862-166e-424c-b8fd-023bfb4f18f2>","WARC-Concurrent-To":"<urn:uuid:ca594c00-269b-4690-b514-f2bfc39c2d69>","WARC-Date":"2017-11-17T17:43:04Z","Content-Length":"21","WARC-Record-ID":"<urn:uuid:df5de410-d4af-45ce-b545-c699e535765f>","WARC-Type":"metadata","Content-Type":"application/warc-fields"},"Block-Digest":"sha1:4SKCIFKJX5QWLVICLR5Y2BYE6IBVMO3Z","Payload-Metadata":{"Actual-Content-Type":"application/metadata-fields","WARC-Metadata-Metadata":{"Metadata-Records":[{"Value":"1140","Name":"fetchTimeMs"}]},"Actual-Content-Length":"21","Trailing-Slop-Length":"0"}}}
이이 후 두 개의 빈 라인을 포함하여 1441 바이트를 차지하는 기록이다.그냥 완성도를 위해서
...
TotalIn
속성은 압축 된 바이트 수는 Gzip으로 머리글과 바닥 글을 포함하지 않는 읽기 반환합니다. 위의 코드에서 GZip에 대한 최소 크기 인 머리글 및 바닥 글 크기에 상수 18 바이트를 사용합니다. 이 파일에서 작동하는 동안 연결 된 GZip 파일을 다루는 다른 사용자는 헤더에 큰 데이터를 추가하는 데이터가 있음을 발견 할 수 있습니다. 위의 데이터는 작동하지 않습니다.
- 직접 Gzip으로 헤더를 구문 분석 및 압축 해제
DeflateStream
를 사용 :이 경우 은 두 가지 옵션이 있습니다.
TotalIn + 18
바이트부터 시작하는 GZip 서명 바이트를 검색합니다.
지나치게 속도를 늦추지 않고 작동해야합니다. 압축 해제 코드에서 버퍼링이 일어나기 때문에 각 세그먼트 후에 스트림을 거꾸로 탐색해야하므로 일부 추가 바이트를 읽는 것이 너무 느려지지는 않습니다.
작은 파일에서도 작동하는지 확인 했습니까? 메가 바이트 정도 되니? 압축되지 않은 원본 파일이 UTF-8로 인코딩 된 것이 확실합니까? 'outmemstream'의 내용을 파일에 써서 거기에 무엇이 있는지 보았습니까? 기억이 안 나올거야? 이 코드는 2 기가 바이트 이상의 RAM (memstream의 경우 280 MB, 압축되지 않은 데이터의 경우 2 배, 작성중인 문자열의 경우 2 배)을 초과하여 먹는 것처럼 보입니다. –
@JimMischel 사실 그것은 그것보다 더 나쁩니다. 압축 된 데이터는 ASCII 텍스트로 보입니다. 비 압축 데이터의 경우 1.2GB, 문자열 표현의 경우 2 배. – Corey