문제

파이썬을 사용하여 데이터를 압축하는 데 관심이 있습니다 gzip 기준 치수. 압축 출력이 결정적이되기를 원합니다. 왜냐하면 일부 비 GZIP 인식 프로세스가 출력, 예를 들어, 예약 또는 IF의 변화를 찾고 있다면 일반적인 것들에게는 종종 편리한 속성이기 때문입니다. 출력은 암호화 적으로 서명 될 것입니다.

불행히도, 출력은 매번 다릅니다. 내가 알 수있는 한, 이에 대한 유일한 이유는 GZIP 헤더의 타임 스탬프 필드입니다. 파이썬 모듈은 항상 현재 시간으로 채워집니다. 나는 당신이 실제로 타임 스탬프없이 GZIP 스트림을 가질 수 있다고 생각하지 않습니다.

어쨌든 Python의 발신자에게는 방법이없는 것 같습니다. gzip 모듈 기본 데이터의 올바른 수정 시간을 제공합니다. (실제 gzip 프로그램은 가능하면 입력 파일의 타임 스탬프를 사용하는 것 같습니다.) 기본적으로 타임 스탬프에 관심이있는 유일한 것은 gunzip 파일에 쓸 때 명령 - 이제 결정 론적 출력을 원하기 때문에 지금. 그게 너무 많이 물어봐?

다른 사람 이이 문제를 겪었습니까?

가장 끔찍한 방법은 무엇입니까? gzip Python의 임의의 타임 스탬프가있는 일부 데이터?

도움이 되었습니까?

해결책

Python 2.7에서 GZIP 헤더에서 사용할 시간을 지정할 수 있습니다. NB 파일 이름도 헤더에 포함되어 있으며 수동으로 지정할 수도 있습니다.

import gzip

content = b"Some content"
f = open("/tmp/f.gz", "wb")
gz = gzip.GzipFile(fileobj=f,mode="wb",filename="",mtime=0)
gz.write(content)
gz.close()
f.close()

다른 팁

예, 당신은 예쁜 옵션이 없습니다. 시간은 _write_gzip_header 에서이 줄로 작성되었습니다.

write32u(self.fileobj, long(time.time()))

그들은 당신에게 시간을 무시할 수있는 방법을 제공하지 않기 때문에, 당신은 다음 중 하나를 할 수 있습니다.

  1. gzipfile에서 수업을 파생시키고 복사하십시오 _write_gzip_header 파생 클래스로 기능하지만이 한 줄에는 다른 값이 있습니다.
  2. GZIP 모듈을 가져 오면 Time Member에 새 코드를 할당하십시오. GZIP 코드에서 이름 시간의 새로운 정의를 기본적으로 제공하므로 시간을 변경할 수 있습니다. 타임 ()가 의미합니다.
  3. 전체 GZIP 모듈을 복사하고 My_Stable_gzip의 이름을 지정하고 필요한 줄을 변경하십시오.
  4. cstringio 객체를 AS FileOBJ에 전달하고 GZIP가 완료된 후 바이트를 수정하십시오.
  5. 작성된 바이트를 추적하는 가짜 파일 객체를 작성하고 자신을 쓰는 타임 스탬프의 바이트를 제외하고 모든 것을 실제 파일로 전달합니다.

다음은 옵션 #2 (비정상적인)의 예입니다.

class FakeTime:
    def time(self):
        return 1225856967.109

import gzip
gzip.time = FakeTime()

# Now call gzip, it will think time doesn't change!

옵션 #5는 GZIP 모듈의 내부에 의존하지 않는 측면에서 가장 깨끗 할 수 있습니다 (테스트되지 않은).

class GzipTimeFixingFile:
    def __init__(self, realfile):
        self.realfile = realfile
        self.pos = 0

    def write(self, bytes):
        if self.pos == 4 and len(bytes) == 4:
            self.realfile.write("XYZY")  # Fake time goes here.
        else:
            self.realfile.write(bytes)
        self.pos += len(bytes)

제출 반점 타임 스탬프의 계산이 고려됩니다. 거의 확실하게 받아 들여질 것입니다.

코벤트리 씨의 조언을 받았습니다 패치를 제출했습니다. 그러나, 파이썬 릴리스 일정의 현재 상태를 고려할 때, 모퉁이에 3.0이 3.0이되면 곧 출시에 나타날 것으로 기대하지 않습니다. 그래도 우리는 무슨 일이 일어나는지 볼 것입니다!

그 동안, 나는 타임 스탬프 필드를 올바르게 설정하는 작은 사용자 정의 필터를 통해 GZIP 스트림을 파이핑하는 Batchelder의 옵션 5를 좋아합니다. 가장 깨끗한 접근 방식처럼 들립니다. 그가 알 수 있듯이, 필요한 코드는 실제로 매우 작지만 그의 예는 (현재 유효한) 가정에 대한 단순성에 달려 있습니다. gzip 모듈 구현은 정확히 4 바이트 호출을 사용하여 타임 스탬프를 작성하도록 선택합니다. write(). 그럼에도 불구하고, 나는 필요한 경우 완전히 일반적인 버전을 생각해내는 것이 매우 어렵다고 생각하지 않습니다.

원숭이 패치 접근 방식 (일명 옵션 2)은 단순성에 대해 유혹적이지만 전화를하는 도서관을 작성하기 때문에 잠시 멈추게합니다. gzip, 독립형 프로그램뿐만 아니라 누군가 전화를 걸려고 할 것 같습니다. gzip 내 모듈이 변경되기 전에 다른 스레드에서 gzip 모듈의 글로벌 상태. 다른 스레드가 비슷한 원숭이 패치 스턴트를 당기려고한다면 이것은 불행한 일입니다! 나는이 잠재적 인 문제가 실제로 나올 가능성이 크지 않다는 것을 인정하지만, 그러한 혼란을 진단하는 것이 얼마나 고통 스러운지 상상해보십시오!

나는 까다로운 일을하려고 노력하는 것을 모호하게 상상할 수 있으며 아마도 어떻게 든 개인적인 사본을 가져 오기 위해 미래를 보이지 않을 것입니다. gzip 모듈 및 원숭이 패치 저것, 그러나 그 시점까지 필터는 더 단순하고 직접적으로 보입니다.

lib/gzip.py에서는 실제로 타임 스탬프가 포함 된 부분을 포함하여 헤더를 작성하는 메소드를 찾습니다. Python 2.5에서 이것은 143 행에서 시작됩니다.

def _write_gzip_header(self):
    self.fileobj.write('\037\213')             # magic header
    self.fileobj.write('\010')                 # compression method
    fname = self.filename[:-3]
    flags = 0
    if fname:
        flags = FNAME
    self.fileobj.write(chr(flags))
    write32u(self.fileobj, long(time.time())) # The current time!
    self.fileobj.write('\002')
    self.fileobj.write('\377')
    if fname:
        self.fileobj.write(fname + '\000')

보시다시피, Time.Time ()을 사용하여 현재 시간을 가져옵니다. 온라인 모듈 문서에 따르면 Time.Time은 "UTC에서 Epoch 이후 몇 초 만에 부동 소수점 번호로 시간을 반환합니다." 따라서 이것을 선택의 부동 소수점 상수로 변경하면 언제든지 동일한 헤더를 작성할 수 있습니다. 시간을 기본값으로 사용하는 동안 사용하는 옵션 시간 매개 변수를 수락하기 위해 라이브러리를 해킹하려고하지 않는 한이 작업을 수행하는 더 좋은 방법을 볼 수 없습니다. 패치를 제출하면 그들은 그것을 좋아할 것입니다!

예쁘지는 않지만 시간을 일시적으로 일시적으로 할 수 있습니다.

import time

def fake_time():
  return 100000000.0

def do_gzip(content):
    orig_time = time.time
    time.time = fake_time
    # result = do gzip stuff here
    time.time = orig_time
    return result

예쁘지는 않지만 아마도 효과가있을 것입니다.

위의 도미니크의 답변과 비슷하지만 기존의 파일:

with open('test_zip1', 'rb') as f_in, open('test_zip1.gz', 'wb') as f_out:
    with gzip.GzipFile(fileobj=f_out, mode='wb', filename="", mtime=0) as gz_out:
         shutil.copyfileobj(f_in, gz_out)

MD5 합계 테스트 :

md5sum test_zip*
7e544bc6827232f67ff5508c8d6c30b3  test_zip1
75decc5768bdc3c98d6e598dea85e39b  test_zip1.gz
7e544bc6827232f67ff5508c8d6c30b3  test_zip2
75decc5768bdc3c98d6e598dea85e39b  test_zip2.gz
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top