۱۳۸۹ آذر ۲۸, یکشنبه

نوشتن و خواندن داده ها به صورت باینری در ++C

نوشتن خروجی و خواندن ورودی به صورت باینری (binary) یکی از ضرورت های برنامه نویسی هست اند. به خصوص وقتی که زمان و حجم داده ها و نتایج در برنامه قابل توجه است. درمقایسه با متن ساده، باینری ها بسیار کوچک تر هستند و نوشتن آنها بر روی دیسک زمان بسیار کمتری می برد. پیچیدگی فایل های باینری خواندن آنهاست که آن هم تنها به یک برنامه ی کوچک خوانش نیاز دارد که برای برنامه نویس های در حد معمولی (مثل خود من) کار آسانی هست. برای یادگیری دستورهای ساده و کلیدی در برنامه ی سی پلاس پلاس این کتاب را پیشنهاد می کنم.


فایل باینری چیست؟
یک فایل باینری، فایلی هست که در آن داده ها به صورت بایت ها ذخیره می شن. بنابراین واحد اولیه داده ها معمولن به صورت پیش فرض به اندازه ی هشت بیت (یک کاراکتر character) هست. در واقع همه ی انواع داده ها در رایانه به صورت دودویی (باینری) هستند. زمانی که ما می خواهیم یک متن ساده را بر روی حافظه ذخیره کنیم، اتفاقی که می افتد این هست که داده ها می بایست ابتدا به متن ساده تبدیل شوند و سپس ذخیره شوند. حال آن که بخشی از این داده ها که تبدی می شوند واقعن لازم نیست اند؛ مثلن یک عدد صحیح (integer) بین دو تا چهار بایت هست که معمولن (بسته به بزرگی عدد) برای ذخیره آن یک بایت (هم اندازه ی یک کاراکتر) کافی هست. به علاوه در حین تبدیل ممکن است دقت را از دست بدهیم؛ مثلن در مورد عددهای اعشاری (double) این اتفاق می افتد چون معمولن تعداد اعشاری که در متن ساده نوشته می شوند کمتر از دقت واقعی متغییر هستند. وحال اگر بخواهیم این متن ساده را زمانی دیگر به عنوان ورودی برنامه استفاده کنیم بخشی از دقت را از دست داده ایم.

در نوشتن به صورت باینری؛ نخست) تبدیلی نیاز نیست، یعنی بخشی از حافظه موقت به همان صورت که هست روی حافظه دایمی ذخیره می شود: تبدیل ها اگرچه چندان زمان بر نیست اند ولی بر کاهش دقت موثر هست اند. دوم) حجم داده ها برای ثبت کمتر خواهد شد: در واقع این نوشتن بر روی حافظه هست که زمانبرترین بخش فرایند ذخیره سازی است و با کم شدن حجم داده ها زمان نوشتن آنها هم طبیعتن کم می شود.


خواندن و نوشتن به صورت باینری
خواندن و نوشتن در باینری تفاوت هایی با متن های ساده دارد. برای مثال وقتی یک فایل باینری باز می شود، برای خواندن، مکان شروع و طول جمله ای که باید خوانده شود را می بایست خودِ برنامه نویس تعریف کند (در واقع برنامه نویس بایستی بداند که داخل فایل چه داده ای با چه شکل و ترتیبی نوشته شده است. به صورت پیش فرض واحد خوانش و نگارش یک کاراکتر هست). مشکل سازگاری یک فایل باینری از یک ماشین به ماشین دیگر هم ممکن است از همین جا باشد. چنانکه مثلن تعریف ابتدا و انتهای یک فایل ممکن است در دو ماشین متفاوت باشد و در نتیجه مکان نما در جای اشتباهی قرار گرفته باشد و در نتیجه فایل باینری در ماشین جدید قابل خواندن نباشد. در فایل باینری مفهمومی مثل پایان خط (end line) و فاصله (space) وجود ندارد.

نوشتن در فایل باینری هم به همین شکل هست؛ در یک فایل باینری اشاره گر شروع می کند به نوشتن پیوسته داده ها بدون در نظر گرفتن هیچ فاصله ی پیش فرضی. به این ترتیب تصحیح باینری ها هم به سادگی باز کردن و نوشتن در یک متن ساده نیست.

به طور کلی در خواندن و نوشتن در C++ می شود از سه کلاس زیر استفاده کرد:

ifstream (input file stream) تنها برای خواندن از یک فایل     
ofstream (outout file stream)تنها برای نوشتن در یک فایل  
fstream (file stream) برای نوشتن و خواندن (هردو) در یک فایل              

بنابراین می شود از کلاس سوم به جای هردوکلاس دیگراستفاده کرد.


برای نوشتن کاراکترها به صورت باینری تنها نام و اندازه ی کاراکتر لازم هست. برای مثال دستور زیر یک کاراکتربا نام Name و اندازه ی ده را به صورت باینری ذخیره می کند:

char Name[10];
ofstream OutFile ("data.bin", ios::out | ios::binary);
OutFile.write (Name, 10);
OutFile.close();

اما اگر داده ها چیزی جز کاراکتر باشند نیاز هست علاوه بر اندازه ی متغیر، اشاره گر را هم به کاراکتر تبدیل کرد مثلن

double Variable;
ofstream OutFile ("data.bin", ios::out | ios::binary);
OutFile.write ((char*)& Variable, sizeof (double));
OutFile.close();


و برای خواندن
double Variable;
ifstream InFile ("data.bin", ios::in | ios::binary);
InFile.read ((char*)&Variable, sizeof (double));
InFile.close();


در شکل و برنامه های بالا به چند چیز دقت کنید:
  1. نوع کلاس برای نوشتن و خواندن متفاوت است.
  2. نام فایل بعد از نام کلاس همان اسمی هست که همه جا در طول برنامه شناخته می شود. اما این نام می تواند متفاوت از نام فایلی باشد که ذخیره می شود.
  3. اولین عبارت در داخل پرانتر نام فایلی هست که داده ها در آن ذخیره خواهند شد یا از آن خوانده خواهند شد.
  4. بعد از اسم فایل مشخصه ورودی-خروجی بودن آمده است. ورودی-خروجی بودن یک فایل بسته به نوع کلاسی هست که استفاده شده. مثلن برای خواندن از ios::in استفاده شده است.
  5. علامت جدا کننده.
  6. نوع فایل (باینری) تعریف شده است.
در مورد نوع فایل و مشخصاتی که فایل می تواند داشته باشد دو جدول در انتهای این متن آمده که می تواند مفید باشد.

برای آزمایش می توانید برنامه ی ساده ای را که نوشته ام دانلود کنید، بخوانید و اجرا کنید. در این برنامه متغییر x در خروجی باینری نوشته می شود و سپس از همان فایل خوانده شده و در متغییر y نوشته می شود. به این ترتیب مقدار نهایی y می بایست برابر با مقدار x باشد. به کلاس هایی که در برنامه به کار رفته اند دقت کنید.

 روی عکس ها کلیک کنید و آنها را در اندازه ی بزرگ ببینید.


پ.ن: اگر سوال یا پیشنهادی در این باره بود خوشجال می شوم بشنوم و اگر توانستم جواب بدهم.

۱ نظر:

ناشناس گفت...

MERSIIIII, AALI BOD