برگزیده های پرشین تولز

كمپرس كردن اطلاعات و فايلها

littlerabbit

مدیر بازنشسته
کاربر فعال
تاریخ عضویت
13 جولای 2003
نوشته‌ها
678
لایک‌ها
6
سن
42
محل سکونت
Iran
متدهای کمپرس کردن دیتا (دلفی)
خیلی پیش میاید که یک برنامه نویس نیاز به کمپرس کردن اطلاعات باشد. مواقعی نظیر پشتیبان گرفتن از اطلاعات یا مثلا وقتی که برنامه نویس دیتابیس میخواهد یک فیلد Blob بزرگ را در یک بانک ذخیره کنید. (مثلا زمانی که نیاز دارید یک Bitmap را به عنوان یک فیلد ذخیره کنید و نمیخواهید با تبدیل آن به Jpg یا هر نوع دیگری قسمتی از آن را از دست بدهید.
در این مواقع متدهای کمپرس بدون تلفات بدرد میخورند. من اینبار سعی دارم که چند متد کمپرس را در اینجا توضیح بدهم و توجه کنید :

کلیه این مطالب برداشت شخصی من از قضیه است و ممکن است درست نباشد من به جز ماخذهایی که ذکر میکنم از هیچ ماخذ دیگری کمک نگرفته ام. هرگونه استفاده از این مطالب آزاد است اما با مسئولیت شخصی خودتان. هر سوالی هم هست لطفا همین جا بپرسید و خواهش میکنم در صورت امکان میل نزنید یا از PM یاهو استفاده نکنید. متشکرم.(دلیلم هم اینست که تا زمانی که فرستنده را نشناسم میل را نمیبینم و به PM های ناشناس هم جواب نمیدهم . بنابراین برای اینکه شرمنده شما نشوم لطفا این کار را نکنید )

من 5 متد کمپرس را میشناسم و با سه تای آنها کار کرده ام. متدها عبارتند از :
-zlib - Bzlib - ucl - lzo - lzma که من با zlib - Bzlib - ucl آشنا هستم و در اینجا آنها را معرفی میکنم. (البته منظور الگوریتم آنها نیست بلکه فقط نحوه استفاده از نمونه پیاده سازی شده آنهاست برای الگوریتم به اطلاعات مربوط به هر کدام رجوع کنید.)
-------------------------------------
1- متد کمپرس zlib
این متد قدیمیترین و یکی از پر استفاده ترین آنهاست. این متد در حال حاضر در جزیی از Linux شده و در PHP و خیلی دیگر از برنامه ها کاملا پشتیبانی میشود. نویسنده کد C مربوط به آن Jean-loup Gailly Mark Adler هستند. این کد Open Source و لیسانس کاملا آزادی دارد. علاوه بر آن تصاویر PNG (Portable network graphic ( هم از این متد برای کمپرس کردن چانک های تصویر استفاده میکند.فایل های gz و tgz نیز با این متد کمپرس شده اند.
نسخه آن را از http://www.info-zip.org/pub/infozip/zlib/ بگیرید. (نسخه فعلی 1.1.4 است )
اما مساله اینجاست که این کد به c است و چطور میتوان از آن در دلفی استفاده کرد؟؟ خیلی ساده! کد را با C++ Builder کامپایل میکنیم و بعد کلیه فایلهای obj موردنیاز را با کمک Compiler Directive مربوطه ($L ) در دلفی جا میدهیم.
البته در مورد zlib دلفی این را از پیش دارد و شما نیازی به این کار ندارید.
اگر سی دی دلفی دارید سورس Zlib ولی نسخه 1.0.4 آن را در پوشه \Info\Extras\Zlib\Src پیدا میکنید. در دلفی قبل از هفت شما باید فایلهای zlib.pas و کلیه فایلهای obj را در مسیر جستجوی دلفی کپی کنید اما در مورد دلفی 7 این کتابخانه در مسیر هست.
البته باید گفت که این کتابخانه نقایصی هم دارد که من ترجیح میدهم از کتابخانه خودم استفاده کنم.(این کتابخانه را به زودی همراه با کد مربوط به bzlib و اگر شد ucl منتشر میکنم)
اما برای کسانی که تمایل به استفاده از کتابخانه Borland را دارند.
گام اول :مطمئن شوید که zlib.pas در مسیر قرار دارد (فقط مربوط به نسخه های قبل از 7 ) اگر نیست از سی دی دلفی آن را کپی کنید. (بالاتر را ببینید )
در این ماژول دو کلاس معرفی شده (در اصل سه تا اما یکی از آنها صرفا به عنوان کلاس والد دو کلاس دیگر است ) سه کلاس مربوط به Exception ها هم هست که ما با آنها زیاد کاری نداریم )
-------------------------------------
کلاس TCustomZlibStream که کلاس والد است. و ما با آن زیاد کاری نداریم. این کلاس از TStream مشتق شده است.
-------------------------------------
کلاس TCompressionStream که برای کمپرس کردن دیتا استفاده میشود.
این کلاس یک متد Create دارد که دو آرگومان میگیرد اولی درجه کمپرس شدن است که میتواند چهار مقدار بگیرد ( None و Default و Fast و Max ) که بسته به نیاز میتوانید انتخاب کنید.
دوم یک Stream در حقیقت این Stream است که کلیه اعمال نوشتن و خواندن را انجام میدهد و TCompressionStream یک Stream واقعی نیست. (از این پس هر جا صحبت از Stream بود منظور این Stream است و نه TCompressionStream یا TDecompressionStream )
یعنی شما احتیاج دارید یک Stream ایجاد کنید (از هر نوع آن منجمله Memory Stream یا File Stream ) و سپس آن را به عنوان جایی که اطلاعات کمپرس شده در آن نوشته میشوند به این Compress Stream پاس بدهید.

در نظر داشته باشید که از این Stream هنگامی که هنوز Compress Stream را تخریب نکرده اید استفاده نکنید در غیر اینصورت ممکن است بعدا با مشکل دکمپرس کردن مواجه شوید و اطلاعات را از دست بدهید. حتی بهتر است اصلا از این Stream به صورت مستقل استفاده نشود.

هر داده ای که میخواهید کمپرس کنید با متد Write در TCompressionStream بنویسید. متد Read را فراخوانی نکنید چون باعث ایجاد ECompressionError میشود.
اما چون متد Zlib یک متد مبتنی بر جریان است (یعنی اینکه یک جریان از بیتها را کمپرس میکند و نه یک بلوک را- برخلاف ucl و lzo - ) شما نمیتوانید مثلا قسمت آخر را اول کمپرس کنید و بعد قسمت اول را. یعنی متد Seek برای جابجا شدن روی TCompressionStream مجاز نیست (مگر در حالت خاص که Origin برابر soFromCurrent و Offsset برابر 0 باشد یعنی اصلا حرکت نکنیم و به عبارتی از خصیصه Position در سمت راست تساوی استفاده کنیم.) و باعث خطای ECompressionError میشود.
یک رویدا - Event - نیز هم هست که هنگامی که عمل کمپرس برای فایلهای بزرگ انجام میشود بدرد خواهد خورد تا برنامه اصطلاحا قفل نکند - مثال را ببینید - اما عیب این رویداد این است که فقط هنگام هر بار نوشتن اجرا میشود اما مقدار بایتی که نوشته شده را اعلام نمیکند. : OnProgress
یک خصیصه - Property - هم هست که مقدار کمپرس را نشان میدهد (کمپرس دیتا تا هر مرحله ای که این خصیصه را بگیریم) : CompressionRate

اما نکته مهم دیگر این است که عمل نوشتن درست همان زمان فراخوانی متد Write انجام نمیشود. و در عوض هر گاه بافر پر شد به یکباره نوشته میشود. یعنی ممکن است شما چندین بار متد Write را فراخوانی کنید اما حتی یک بایت نوشته نشود و بعد با نوشتن یک بایت به یکباره کل اطلاعات قبلی نوشته شود. این به معنی این است که عمل نوشتن تکمیل نخواهد شد مگر اینکه شما دست آخر شی را تخریب کنید. و حتما به یاد داشته باشید که شی TCompressionStream بایستی قبل از Stream که به آن پاس داده شده تخریب شود.
-------------------------------------
کلاس TDecompressionStream که برای دکمپرس کردن دیتا استفاده میشود.
این کلاس متد Create دارد که یک آرگومان میگیرد این آرگومان همان Stream است که در بالا برای TCompressionStream توضیح داده شد. البته اینبار از این Stream برای خواندن اطلاعات استفاده میشود نه مثل TCompressionStream برای نوشتن اطلاعات.
کلیه نکاتی را که در مورد این Stream در TCompressionStream گفته شد در مورد این هم صادق است.
در این مورد متد Write باعث خطای EDecompressionError میشود یعنی فقط از TDecompressionStream میتوان اطلاعات خواند.
متد Read اطلاعات را از Stream میخواند و دکمپرس کرده و آن را به شما تحویل میدهد.
متد Seek تنها زمانی مجاز است که بخواهیم به موقعیتی بعد از موقعیت فعلی برویم و یا اینکه به اول برگردیم. (در مورد موقعیتی بعد از موقعیت فعلی این فاصله همینطور الکی دکمپرس میشود) در غیر اینصورت با EDecompressionError مواجه میشوید.
متد OnProgress هم هست درست مثل TCompressionStream
-------------------------------------
اما در مورد فایلهای gz و فایلهای tgz ( یا tar.gz ) این نوع فایلها با این متد کمپرس شده اند. بر خلاف فایلهای bz2 (متد کمپرس bzip یا bzlib ) که خودش هدر و crc را در آن مینویسد این فایلها هدر ساده ای دارند و بعد از آن هدر اطلاعات کمپرس شده و بعد crc فایل در حالت کمپرس نشده و سپس حجم فایل کمپرس نشده قرار دارد. که این اطلاعات را zlib در ایل نمینویسد و برنامه خود باید آنها را بنویسد.
یکی دیگر از نقاط ضعف کتابخانه zlib دلفی این است که یکی از قابلیتهایی که برای ایجاد فایلهای gz لازم است را پشتیبانی نمیکند
در zlib هنگامی که یک فایل (یا در حالت کلی یک جریان از بایتها )را کمپرس میکنیم zlib چند بایت را به عنوان هدر بر سر فایل کمپرس شده میگذارد.(منظور هدر فایل gz نیست یک هدر مربوط به خود zlib) در صورتی که برای فایلهای gz باید این هدر کنار گذاشته شود. برای کمپرس کردن میتوان از این بایتها صرف نظر کرد و آنها را در فایل ننوشت اما موقع دکمپرس کردن در صورتی که این فایلها نباشند zlib شما را با خطا متوقف میکند.

این قابلیت (در نظر نگرفتن هدر ) در کتابخانه من هست که همانطور که گفتم با سر و سامان دادن به کد آن را منتشر میکنم.

برای گرفتن اطلاعات بیشتر به rfc - Request for Comment شماره های 1950 تا 1952 مراجعه کنید :

اولی در مورد ساختار دیتا در حالت کمپرس شده zlib است
http://www.rfc-editor.org/rfc/rfc1950.txt
دومی در مورد الگوریتم DEFLATE که تنها الگوریتم کمپرس کردن دیتاست که در zlib پشتیبانی میشود.
http://www.rfc-editor.org/rfc/rfc1951.txt
سومی در مورد ساختار فایل gz است.
http://www.rfc-editor.org/rfc/rfc1952.txt
این سه منبع تنها رفرنس های من در مورد این مطلب بوده اند.

یکی از معایب فایل gz این است که فقط یک فایل را در خود کمپرس میکند . فایلهای tar نوعی آرشیو است که هیچ گونه کمپرسی انجام نمیدهد بلکه فایلها را در یک فایل با ساختار پوشه های آن جای میدهد. ترکیب فایلهای tar و gz را معمولا با پسوند tgz یا tar.gz نشان میدهند. و برای کمپرس کردن تعداد زیادی فایل مناسب است.
فایل gz هیچ گونه اطلاعاتی از فایل کمپرس شده را در خود نگه نمیدارد و برای حفظ پسوند آن معمولا اسم فایل gz پسوند را با خود دارد مثلا پسوند .bmp.gz یعنی یک فایل bmp که با این متد کمپرس شده است.

میتوان از این کتابخانه برای خواندن فایلهای zip هم استفاده کرد میتوانید در سورس zlib یک برنامه برای این کار ببینید : minizip

برای اطلاعات بیشتر برنامه Delph را که Attach شده بببینید.
کاربرهای وی بی میتوانند از zlib.dll برای استفاده از zlib کمک بگیرند (حوصله ندارم اما اگر شد کد آن را مینویسم )


ps :
اگر حوصله شد و توانستم در مورد باقی این متد ها هم مینویسم اما شاید حتی تا ماهها بعد... لطفا پیوستگی مطالب را حفظ کنید تا مجبور به حذف پستها یا قفل کردن تاپیک نشوم .

با تشکر - فرود (خرگوش کوچولو)
 

فایل های ضمیمه

  • zlib.zip
    3.1 KB · نمایش ها: 199

littlerabbit

مدیر بازنشسته
کاربر فعال
تاریخ عضویت
13 جولای 2003
نوشته‌ها
678
لایک‌ها
6
سن
42
محل سکونت
Iran
متشكرم كه تعريف كرديد اما با مهرداد هم موافقم . لطفا رعايت كنيد.
 
بالا