2010-09-29 15 views
8

मैं डेटाबेस से पूछताछ कर रहा हूं और पाइथन का उपयोग करके परिणामों को संग्रहित कर रहा हूं, और मैं डेटा को संपीड़ित करने की कोशिश कर रहा हूं क्योंकि मैं इसे लॉग फ़ाइलों में लिखता हूं। हालांकि, मुझे इसके साथ कुछ समस्याएं आ रही हैं।संपीड़न कोडेक्स पाइथन में कैसे काम करते हैं?

मेरे कोड इस तरह दिखता है:

log_file = codecs.open(archive_file, 'w', 'bz2') 
for id, f1, f2, f3 in cursor: 
    log_file.write('%s %s %s %s\n' % (id, f1 or 'NULL', f2 or 'NULL', f3)) 

लेकिन, मेरा आउटपुट फ़ाइल 1,409,780 के आकार की है। फ़ाइल परिणामों पर bunzip2 चल रहा है जिसमें 943,634 के आकार वाली फ़ाइल है, और bzip2 चल रहा है, जिसके परिणामस्वरूप 217,275 के आकार में। दूसरे शब्दों में, असम्पीडित फ़ाइल पाइथन के bzip कोडेक का उपयोग करके संपीड़ित फ़ाइल से काफी छोटी है। क्या कमांड लाइन पर bzip2 चलाने के अलावा इसे ठीक करने का कोई तरीका है?

मैंने पाइथन के जीजीआईपी कोडेक (codecs.open(archive_file, 'a+', 'zip') पर लाइन को बदलने) को यह देखने के लिए प्रयास किया कि यह समस्या ठीक हो गई है या नहीं। मुझे अभी भी बड़ी फाइलें मिलती हैं, लेकिन जब मैं फ़ाइल को असम्पीडित करने का प्रयास करता हूं तो मुझे gzip: archive_file: not in gzip format त्रुटि भी मिलती है। वहां क्या चल रहा है?


संपादित: मैं मूल रूप से फ़ाइल संलग्न मोड में खोला था, नहीं मोड लिखें। हालांकि यह समस्या हो सकती है या नहीं भी हो सकती है, फिर भी सवाल तब होता है जब फ़ाइल 'डब्ल्यू' मोड में खोली जाती है।

+0

आप संलग्न करने के लिए फ़ाइल क्यों खोल रहे हैं? – JoshD

+0

यह धीरे-धीरे डेटाबेस से रिकॉर्ड्स को ट्रिम करता है और उन्हें एक संग्रह फ़ाइल में सहेजता है, इसलिए संग्रह फ़ाइल धीरे-धीरे तब तक बढ़ती है जब तक यह मशीन से कॉपी नहीं हो जाती है। –

उत्तर

2

जैसा कि अन्य पोस्टर ने नोट किया है, मुद्दा यह है कि codecs लाइब्रेरी डेटा को एन्कोड करने के लिए एक वृद्धिशील एन्कोडर का उपयोग नहीं करती है ; इसके बजाय यह संपीड़ित ब्लॉक के रूप में write विधि को खिलाए गए डेटा के प्रत्येक स्निपेट को एन्कोड करता है। यह बहुत अक्षम है, और स्ट्रीम के साथ काम करने के लिए डिज़ाइन की गई लाइब्रेरी के लिए केवल एक भयानक डिज़ाइन निर्णय है।

विडंबना यह है कि पहले से ही पाइथन में निर्मित एक बिल्कुल उचित वृद्धिशील बीजी 2 एन्कोडर है। "फ़ाइल जैसी" कक्षा बनाना मुश्किल नहीं है जो सही चीज़ को स्वचालित रूप से करता है।

import bz2 

class BZ2StreamEncoder(object): 
    def __init__(self, filename, mode): 
     self.log_file = open(filename, mode) 
     self.encoder = bz2.BZ2Compressor() 

    def write(self, data): 
     self.log_file.write(self.encoder.compress(data)) 

    def flush(self): 
     self.log_file.write(self.encoder.flush()) 
     self.log_file.flush() 

    def close(self): 
     self.flush() 
     self.log_file.close() 

log_file = BZ2StreamEncoder(archive_file, 'ab') 

एक चेतावनी: इस उदाहरण में, मैं संलग्न मोड में फ़ाइल को खोल लेते; एक ही फ़ाइल में एकाधिक संपीड़ित धाराओं को जोड़ना bunzip2 के साथ पूरी तरह से अच्छी तरह से काम करता है, लेकिन पाइथन स्वयं इसे संभाल नहीं सकता है (हालांकि इसके लिए is a patch)। यदि आपको संपीड़ित फ़ाइलों को पढ़ने की आवश्यकता है जो आप पाइथन में वापस बनाते हैं, तो प्रति फ़ाइल एक स्ट्रीम पर चिपके रहें।

0

समस्या आपके एपेंड मोड के उपयोग के कारण है, जिसके परिणामस्वरूप फाइलों के कई संपीड़ित ब्लॉक होते हैं। इस उदाहरण को देखें:

>>> import codecs 
>>> with codecs.open("myfile.zip", "a+", "zip") as f: 
>>>  f.write("ABCD") 

मेरे सिस्टम पर, यह आकार में 12 बाइट्स फ़ाइल बनाता है। चलो देखते हैं कि इसमें क्या है:

>>> with codecs.open("myfile.zip", "a+", "zip") as f: 
>>>  f.write("EFGH") 

फ़ाइल अब आकार में 24 बाइट्स की है, और उसकी सामग्री हैं::

>>> with codecs.open("myfile.zip", "r", "zip") as f: 
>>>  f.read() 
'ABCD' 

>>> with codecs.open("myfile.zip", "r", "zip") as f: 
>>>  f.read() 
'ABCD' 

ठीक है, अब के संलग्न मोड में एक और लिखने करते हैं

यहां क्या हो रहा है यह है कि अनजिप एक ज़िप्ड स्ट्रीम की अपेक्षा करता है। आपको यह देखने के लिए चश्मे की जांच करनी होगी कि आधिकारिक व्यवहार एकाधिक समेकित धाराओं के साथ क्या है, लेकिन मेरे अनुभव में वे पहले प्रक्रिया को संसाधित करते हैं और शेष डेटा को अनदेखा करते हैं। यही वह है जो पायथन करता है।

मुझे उम्मीद है कि bunzip2 वही काम कर रहा है। तो वास्तव में आपकी फ़ाइल संपीड़ित है, और इसमें मौजूद डेटा से बहुत छोटा है। लेकिन जब आप इसे bunzip2 के माध्यम से चलाते हैं, तो आप केवल उस रिकॉर्ड के पहले सेट को वापस प्राप्त कर रहे हैं जिसे आपने लिखा था; बाकी को त्याग दिया जाता है।

+0

सबसे पहले, आकार अंतर एक बार प्रोग्राम चलाने के परिणाम हैं। 'डब्ल्यू' के साथ इसे चलाने से सटीक उसी फ़ाइल का उत्पादन होता है जो 'ए +' करता है, जो असम्पीडित संस्करण से लगभग 30% बड़ा होता है। दूसरा, हालांकि पाइथन डेटा के पहले संपीड़ित ब्लॉक से पहले नहीं पढ़ता है, "bunzip2" करता है। –

0

मुझे यकीन नहीं है कि यह करने के लिए कोडेक्स से यह कितना अलग है, लेकिन यदि आप gzipfile से gzipFile का उपयोग करते हैं तो आप फ़ाइल में वृद्धि कर सकते हैं लेकिन यह बहुत अच्छी तरह से संपीड़ित नहीं होगा जब तक आप बड़ी मात्रा में लिख नहीं रहे एक समय में डेटा (शायद> 1 केबी)। यह सिर्फ संपीड़न एल्गोरिदम की प्रकृति है। यदि आप जो डेटा लिख ​​रहे हैं वह बहुत महत्वपूर्ण नहीं है (यानी यदि आप अपनी प्रक्रिया मर जाते हैं तो आप इसे खोने से निपट सकते हैं) तो आप आयातित कक्षा को लपेटकर एक buffered GzipFile क्लास लिख सकते हैं जो डेटा के बड़े हिस्से लिखता है।

1

समस्या यह प्रतीत होती है कि प्रत्येक write() पर आउटपुट लिखा जा रहा है। यह प्रत्येक लाइन को अपने स्वयं के bzip ब्लॉक में संपीड़ित करने का कारण बनता है।

मैं फ़ाइल में लिखने से पहले स्मृति में एक बहुत बड़ी स्ट्रिंग (या प्रदर्शन के बारे में चिंतित होने पर स्ट्रिंग्स की सूची) बनाने का प्रयास करूंगा। शूट करने के लिए एक अच्छा आकार 900K (या अधिक) होगा क्योंकि यह ब्लॉक आकार है कि bzip2