2011-02-08 12 views
12

मैं एक स्क्रिप्ट लिख रहा हूं जो gzip धाराओं के रूप में उपकरण से आने वाले डेटा के साथ काम करेगा। लगभग 9 0% मामलों में, gzip मॉड्यूल पूरी तरह से काम करता है, लेकिन कुछ धाराएं इसे IOError: Not a gzipped file उत्पन्न करती हैं। यदि gzip हेडर हटा दिया गया है और डिफ्लेट स्ट्रीम सीधे zlib पर खिलाया गया है, तो मुझे इसके बजाय Error -3 while decompressing data: incorrect header check मिलता है। दीवार के खिलाफ मेरे सिर को टक्कर देने के आधे दिन के बाद, मैंने पाया कि जिन धाराओं में समस्याएं आ रही हैं उनमें अंतराल में अतिरिक्त बाइट्स (जो कि जीजीआईपी डेटा का हिस्सा नहीं हैं) शामिल हैं।मैं Gzip फ़ाइलों के साथ कैसे काम कर सकता हूं जिसमें अतिरिक्त डेटा है?

यह मुझे अजीब लगा कि अजगर दो कारणों से इन फाइलों के साथ काम नहीं कर सकते हैं के रूप में हमलों:

  1. दोनों Gzip और 7zip मुद्दे के बिना इन "गद्देदार" फ़ाइलें खोलने के लिए सक्षम हैं। (। Gzip संदेश decompression OK, trailing garbage ignored, 7zip चुपचाप सफल होता है पैदा करता है)
  2. दोनों Gzip और अजगर डॉक्स संकेत मिलता है कि यह काम करना चाहिए लगता है: (जोर मेरा)

    Gzip's format.txt:

    यह संभव होना चाहिए संपीड़ित डेटा के वास्तविक आकार के बावजूद किसी भी संपीड़न विधि, के साथ संपीड़ित डेटा के अंत का पता लगाएं। विशेष रूप से, decompressor एक रिकार्ड उन्मुख फाइल सिस्टम पर एक वैध संपीड़ित फ़ाइल को संलग्न अतिरिक्त डेटा का पता लगाने और छोड़ने के लिए, या में सक्षम होना चाहिए जब संकुचित डेटा केवल एक के गुणकों में एक डिवाइस से पढ़ा जा सकता है कुछ ब्लॉक आकार।

    Python's gzip.GzipFile`:

    एक GzipFile वस्तु की close() विधि कॉलिंग fileobj, बंद नहीं होती है जब से तुम संकुचित डेटा के बाद और अधिक सामग्री संलग्न करने के लिए इच्छा हो सकती है। यह आपको ऑब्जेक्ट को fileobj के रूप में लिखने के लिए खोला गया है, और StringIO ऑब्जेक्ट की getvalue() विधि का उपयोग करके परिणामी मेमोरी बफर पुनर्प्राप्त करने की अनुमति देता है।

    Python's zlib.Decompress.unused_data:

    एक स्ट्रिंग जो संकुचित डेटा के अंत अतीत किसी भी बाइट का है। यही है, यह संपीड़न डेटा युक्त अंतिम बाइट तक "" बनी हुई है। यदि संपूर्ण स्ट्रिंग संपीड़ित डेटा को शामिल करने के लिए निकली है, तो यह खाली स्ट्रिंग "" है।

    यह निर्धारित करने का एकमात्र तरीका है कि संकुचित डेटा समाप्त होने की स्ट्रिंग वास्तव में इसे डिकंप्रेस कर रही है। इसका अर्थ यह है कि जब संपीड़ित डेटा में एक बड़ी फ़ाइल का हिस्सा होता है, तो आप केवल डेटा को पढ़ने और इसे कुछ गैर-खाली स्ट्रिंग द्वारा किसी डिकंप्रेशन ऑब्जेक्ट के decompress() विधि में तब तक प्राप्त कर सकते हैं जब तक unused_data विशेषता अब नहीं है खाली स्ट्रिंग।

यहाँ चार दृष्टिकोण मैं कोशिश की है कर रहे हैं।

# approach 1 - gzip.open 
with gzip.open(filename) as datafile: 
    data = datafile.read() 

# approach 2 - gzip.GzipFile 
with open(filename, "rb") as gzipfile: 
    with gzip.GzipFile(fileobj=gzipfile) as datafile: 
     data = datafile.read() 

# approach 3 - zlib.decompress 
with open(filename, "rb") as gzipfile: 
    data = zlib.decompress(gzipfile.read()[10:]) 

# approach 4 - zlib.decompressobj 
with open(filename, "rb") as gzipfile: 
    decompressor = zlib.decompressobj() 
    data = decompressor.decompress(gzipfile.read()[10:]) 

मैं कुछ गलत कर रहा हूँ (इन उदाहरणों अजगर 3.1 हैं, लेकिन मैं 2.5 2.7 परीक्षण किया है और और एक ही समस्या थी।)?

अद्यतन

ठीक है, जबकि gzip के साथ समस्या यह मॉड्यूल में एक बग हो रहा है, मेरे zlib समस्याओं स्व-प्रेरित कर रहे हैं। ;-)

gzip.py में खोदने के दौरान मुझे एहसास हुआ कि मैं क्या गलत कर रहा था - डिफ़ॉल्ट रूप से, zlib.decompress et al। zlib-wrapped धाराओं की अपेक्षा करें, नंगे डिफ्लेट स्ट्रीम न करें। wbits के लिए ऋणात्मक मान में गुजरकर, आप zlib शीर्षलेख को छोड़ने और कच्ची धारा को डीक्रोप्रेस करने के लिए zlib बता सकते हैं। इन दोनों कार्य:

# approach 5 - zlib.decompress with negative wbits 
with open(filename, "rb") as gzipfile: 
    data = zlib.decompress(gzipfile.read()[10:], -zlib.MAX_WBITS) 

# approach 6 - zlib.decompressobj with negative wbits 
with open(filename, "rb") as gzipfile: 
    decompressor = zlib.decompressobj(-zlib.MAX_WBITS) 
    data = decompressor.decompress(gzipfile.read()[10:]) 

उत्तर

18

यह एक बग है। पायथन में gzip मॉड्यूल की गुणवत्ता गुणवत्ता से बहुत कम है जो पाइथन मानक पुस्तकालय में आवश्यक होनी चाहिए।

समस्या यह है कि gzip मॉड्यूल मानता है कि फ़ाइल gzip-format फ़ाइलों की एक धारा है। संपीड़ित डेटा के अंत में, यह एक नया gzip शीर्षलेख की उम्मीद, स्क्रैच से शुरू होता है; अगर यह एक नहीं मिलता है, तो यह एक अपवाद उठाता है। ये गलत है।

बेशक

, यह दो gzip फ़ाइलें, जैसे श्रेणीबद्ध करने के लिए मान्य है:

echo testing > test.txt 
gzip test.txt 
cat test.txt.gz test.txt.gz > test2.txt.gz 
zcat test2.txt.gz 
# testing 
# testing 

gzip मॉड्यूल की त्रुटि है कि यह एक अपवाद नहीं है अगर कोई gzip के आसपास दूसरी बार हेडर उठाना नहीं होनी चाहिए; यह बस फ़ाइल को खत्म करना चाहिए। इसे केवल अपवाद बढ़ाएं यदि पहली बार कोई शीर्षलेख नहीं है।

सीधे gzip मॉड्यूल को संशोधित किए बिना कोई साफ वर्कअराउंड नहीं है; यदि आप ऐसा करना चाहते हैं, तो _read विधि के नीचे देखें। इसे एक और झंडा सेट करना चाहिए, उदाहरण के लिए। reading_second_block, IOError के बजाय EOFError बढ़ाने के लिए _read_gzip_header बताने के लिए।

इस मॉड्यूल में अन्य बग भी हैं। उदाहरण के लिए, यह अनावश्यक रूप से खोजता है, जिससे यह नेटवर्क सॉकेट जैसे गैर-निष्पादन योग्य धाराओं में विफल हो जाता है। यह मुझे इस मॉड्यूल में बहुत कम आत्मविश्वास देता है: एक डेवलपर जो यह नहीं जानता कि जीजीआईपी को बिना मांग किए काम करने की ज़रूरत है, उसे पाइथन मानक पुस्तकालय के लिए लागू करने के लिए बुरी तरह अयोग्य है।

+0

मैं वास्तव में समस्या को दूर करने, जबकि 'gzip' के internals के साथ एक सा बारे में mucked चाहते हैं, लेकिन इसे ठीक करने के मेरे लिए नहीं हुआ था वहां समस्या और मेरी स्क्रिप्ट के साथ संशोधित मॉड्यूल पैकेज।यह नरक के रूप में बदसूरत है, लेकिन ऐसा लगता है कि यह अभी भी सबसे अच्छा उपलब्ध विकल्प हो सकता है। : -/ –

+0

@ बेन: यह स्वयं निहित है कि कम से कम एक बड़ी लागत नहीं है; सिर्फ एक फाइल यह देशी मॉड्यूल के साथ और अधिक परेशान है। –

+0

एक काम के रूप में, यह मानते हुए कि यह आपके कोड पर आकार या समय की बाधाओं को तोड़ नहीं देता है, आप त्रुटि प्राप्त करने के बाद एक बाइट में पढ़ सकते हैं। एक सूची में प्रत्येक बाइट संलग्न करें, जब आप 'gzipped फ़ाइल नहीं' पैरामीटर के साथ एक और IOError प्राप्त करते हैं, तो आप डेटा के अंत तक पहुंच गए हैं, '' इसमें शामिल हों और –

4

मुझे अतीत में एक ही समस्या थी। मैंने new module लिखा जो धाराओं के साथ बेहतर काम करता है। आप इसे आज़मा सकते हैं और देख सकते हैं कि यह आपके लिए काम करता है या नहीं।

+3

कभी भी अपने फिक्स को मानक gzip मॉड्यूल में विलय करने पर विचार किया जाता है? – Karmastan

+0

मैंने इसे माना, लेकिन जैसा कि यह है कि इसमें ढांचे के दूसरे हिस्से पर निर्भरता है। हालांकि, इसे ठीक करना आसान होना चाहिए। – Keith

-1

मैं इसे उपर्युक्त तकनीकों के साथ काम करने के लिए नहीं बना सका। इसलिए पैकेज zipfile का उपयोग कर

import zipfile 
from io import BytesIO 
mock_file = BytesIO(data) #data is the compressed string 
z = zipfile.ZipFile(file = mock_file) 
neat_data = z.read(z.namelist()[0]) 

सही काम करता है के चारों ओर एक काम बना

संबंधित मुद्दे

 संबंधित मुद्दे