انواع فايل از نظر نوع اطلاعات

داده ها ممكن است در فايل به دو صورت ذخيره شوند:۱ـ اسكي يامتن(text) 2ـ بانيري(binary)

اين دو روش ذخيره شدن داده ها در موارد زير با يكديگر تفاوت دارند:
۱ـ تعيين انتهاي خط
۲ـ تعيين انتهاي فايل

۳ـ نحوه ذخيره شدن اعداد بر روي ديسك
در فايل متني اعداد به صورت رشته أي از كاراكتر ذخيره مي شوند ولي در فايل بانيري اعداد به همان صورتي كه در حافظه قرار مي گيرند بر روي ديسك ذخيره مي گردند.

در فايل متني، كاراكتري كه پايان خط را مشخص مي كند در حين ذخيره شدن بر روي ديسك بايد به كاراكترهاي CR/LF بايد به كاراكترها تعيين كننده پايان خط تبديل شوند و بديهي است كه اين تبديلات مستلزم صرف وقت است. لذا دسترسي به اطلاعات موجود در فايلهاي متني كندتر از فايلهاي بانيري است. اختلاف ديگر فايلهاي متني و بانيري در تشخيص انتهاي فايل است. در مورد روش ذخيره فايل ها طول فايل توسط سيستم نگهداري مي شود و انتهاي فايل با توجه به اين طول مشخص مي گردد در حالت متني كاراكتر ۱A ( در مبناي ۱۶) و با ۲۶( در مبناي ۱۰) مشخص كننده انتهاي فايل است( اين كاراكتر با فشار دادن

كليدCTRL به همراه كليدZ توليد مي‌شود.) در حين خواندن داده ها فايل ها متني وقتي كنترل به اين كاراكتر ها رسيد، بيانگر اين است كه داده هاي موجود در فايل تمام شده اند. در فايل بانيري ممكن است عدد ۱A (در مبناي ۱۶) و يا ۲۶(در مبناي ۱۰) جزئي از اطلاعات بوده بيانگر انتهاي فايل نباشد. لذا نحوه تشخيص انتهاي فايل در فايل بانيري با فايل متني متفاوت است.

 

سازمان فايل
منظور از سازمان فايل اين است كه اطلاعات در فايل چگونه ذخيره مي شوند و سپس به چه روشهايي مورد بازيابي قرار مي گيرند. به عبارت ديگر قانون حاكم بر نحوه ذخيره و بازيابي داده ها را در فايل، سازمان فايل گويند.

در اين فصل به دو سازمان فايل پرداخته مي شود:
۱ـ سازمان فايل ترتيبي(scquenital)
2ـ سازمان فايل تصادفي(random)
در سازمان فايل ترتيبي، ركوردها بهمان ترتيبي كه از ورودي خوانده مي شوند در فايل قرار مي گيرند و در هنگام بازيابي به همان ترتيب كه در فايل ذخيره شده اند مورد
بررسي قرار مي گيرند.
فايل هاي ترتيبي معمولاً داراي يك فيلد كليد هستند( فيلد كليد، فيلدي است كه به عنوان شاخص ركورد مورد استفاده قرار مي گيرد.) و بر اساس آن مرتب مي باشند. در سازمان فايل تصادفي، به هر ركورد يك شماره اختصاص مي يابد لذا اگر فايل داراي n ركورد باشد ركوردها ۱ تاn شماره گذاري خواهند شد. وقتي كه ركوردي در فايلي با سازمان تصادفي قرار گرفت محل آن توسط يك الگوريتم پيدا كننده آدرس كه با فيلد كليد ارتباط دارد مشخص مي شود. در اين صورت دو ركورد با فيلد كليد مساوي، نمي توانند در فايل تصادفي وجود داشته باشند. در سازمان فايل تصادفي مستقيماً مي توان به ر ركورد دلخواه دسترسي پيدا كرد.( بدون اينكه ركوردهاي قبل خوانده شوند.)

باز كردن فايل
هر فايل قبل از اينكه بتواند مورد استفاده قرار گيرد بايد باز شود. مواردي كه در حين باز كردن فايل مشخص مي شود عبارتند از:
۱ـ نام فايل
۲ـ نوع فايل از نظر ذخيره اطلاعات متني يا بانيري
۳ـ نوع فايل از نظر ورودي ـ خروجي( آيا فايل فقط به عنوان ورودي است. آيا فقط خروجي يا هر دو)

يك فايل ممكن است طوري باز شد كه فقط عمل نوشتن اطلاعات بر روي آن مجاز باشد. به چنين فايلي، فايل خروجي گفته مي شود. اگر فايل طوري باز گردد كه فقط عمل خواندن اطلاعات از آن امكان پذير باشد به چنين فايلي، فايل ورودي گفته مي شود. اگر فايل طوري باز شود كه هم عمل نوشتن اطلاعات بر روي آن مجاز باشد و هم عمل خواندن اطلاعات از آن، به چنين فايلي ورودي ـ خروجي گفته مي شود. اگر فايلي قبلاً وجود داشته باشد و به عنوان خروجي باز گردد اطلاعات قبلي آن از بين مي رود. براي باز كردن فايل از تابع fopen() استفاده مي گردد. اين تابع كه در فايل stdio.h قرار دارد به صورت زير به كار مي رود:
FILE* fopen(char *filename,*mode)

در اين الگوfilename به رشته أي اشاره مي كند كه حاوي نام فايل و محل تشكيل يا وجود آن است. نام فايل داده از قانون نام گذاري فايل برنامه تبعيت مي كند و شامل دو قسمت نام و پسوند است. بهتر است پسوند فايل داده،dat انتخاب گردد. محل تشكيل يا وجود فايل مي تواند شامل نام درايو و يا مسير موجود روي ديسك باشد.mode مشخص مي كند كه فايل چگونه بايد باز شود( ورودي و يا خروجي و يا ورودي ـ خروجي) مقاديري كه مي تواند به جاي mode در تابعfopen( ) قرار گيرند. همراه با مفاهيم آنها در جدول زير:

mode مفهوم
r(r t) فايلي از نوع Text را به عنوان ورودي باز مي كند.
w(wt) فايلي از نوع Text را به عنوان خروجي باز مي كند.

a(at) فايلي را طوري باز مي كند كه بتوان اطلاعاتي را به انتهاي آن اضافه نمود
(rb) فايلي از نوع بانيري را به عنوان ورودي باز مي كند.

wb فايلي از نوع بانيري را به عنوان خروجي باز مي كند.
ab فايل موجود از نوع بانيري را طوري باز مي كند كه بتوان اطلاعات را به انتهاي آن اضافه نمود.
r+(r+t) فايل موجود از نوع Text را به عنوان ورودي و خروجي باز مي كند.
w+(w+t) فايلي از نوع Text را به عنوان ورودي و خروجي باز مي كند.

a+(a+t) فايل موجود از نوع Text را به عنوان ورودي و خروجي باز مي كند.
r+b فايل موجود از نوع بانيري را به عنوان و خروجي باز مي كند.
w+b فايل از نوع بانيري را به عنوان ورودي و خروجي باز مي كند.

a+b فايل از نوع بانيري را به عنوان ورودي و خروجي باز مي كند.
براي باز كردن فايل بايد يك اشاره گر از نوع فايل تعريف گردد تا به فايلي كه توسط تابع fopen باز مي شود اشاره نمايد. اگر فايل به دلايلي باز نشود اين اشاره گر برابر با null خواهد بود. به عنوان مثال دستورات زير را در نظر بگيريد:
(۱) FILE*fp
(2) —
دستور ۱، متغير fp را از نوع اشاره گر فايل تعريف مي كند و دستور ۲، فايلي به نام text را بر روي درايو A ايجاد مينمايد.( زيرا حالت “w” ، فايل را به صورت خروجي باز مي كند.)FILE ماكرويي در فايل stdio.h است. براي تشخيص اينكه آيا فايل با موفقيت باز شده است يا خير مي توان اشاره گر فايل را Null مقايسه كرد.(Null ماكرويي است كه در فايل stdio.h تعريف شده است و با حروف بزرگ به كار مي‌رود) اگر اشاره گر فايل برابر با Null باشد بدين معني است كه فايل باز شده است:
if((fp=fopen(“A:test”,”w”))==Null{
print f(“can not open file \n”);
exit(0);
}
بستن فايل
پس از اينكه برنامه نويس كارش را با فايل تمام كرد بايد آن را ببندد. بستن فايل توسط تابع fclose( ) انجام مي شود كه داراي الگوي زير است:
int fclose(FILE * fp)
در الگوي فوق،fp به فايلي اشاره مي كند كه بايد توسط fclose ( ) بسته شود. به عنوان مثال، دستورfclose (p) فايلي را كه p به آن اشاره مي كند مي بندد. اگر چندين فايل به طور همزمان در برنامه باز باشند مي توان آنها را با تابعfcloseall( ) بست. اين تابع به صورت زير به كار مي رود:
fcloseall( );
ورودي ـ خروجي كاراكترها
براي نوشتن يك كاراكتر در فايل، از توابع fputc( ),putc( ) استفاده مي شود. عملكرد اين دو تابع يكسان است. تابع putc( ) در گونه هاي جديدfputc( ),C در گونه هاي قديميC وجود داشته است. سرعت تابعputc( ) از تابعfputc( ) بيشتر است. لذا در اينجا از تابع putc( ) استفاده مي شود الگوي اين تابع به صورت زير است:
int putc (int ch,FILE*fp)
در الگوي فوق،ch كاراكتري است كه بايد در فايل نوشته شود وfp اشاره گري از نوع فايل است كه مشخص مي كند كاراكتر مورد نظر بايد در چه فايلي نوشته شود.
براي خواندن كاراكترها از فايل، مي توان از دو تابعfgetc( ),getc( ) استفاده نمود. نحوه بكارگيري اين دو تابع يكسان است. تابعfgetc( ) در گونه هاي قديمي getc( ),C در گونه هاي جديد C وجود دارد. سرعت اجراي تابعgetc( ) از تابع fgetc( ) بيشتر است، لذا در اينجا از تابع getc( ) استفاده مي شود. الگوي اين تابع به صورت زير است:
int getc(FILE* fp)
در الگوي فوق fp اشاره گري است كه مشخص مي كند كاراكتر مورد نظر از كدام فايل بايد خوانده شود.
در مورد خواندن و نوشتن داده ها بر روي فايل بايد به نكات زير توجه داشت:
۱ـ وقتي كاراكترهايي بر روي فايل نوشته مي شوند. بايد مكان بعدي، كه كاراكتر آتي در آنجا قرار مي گيرد مشخص باشد؛ همچنين وقتي كه كاراكترهايي از فايل خوانده مي شوند بايد مشخص باشد كه تاكنون تا كجاي فايل خوانده شده است و كاراكتر بعدي از كجا بايد خوانده شود. براي اين منظور، سيستم از يك متغير به نام“ موقعيت سنج فايل”(file position) استفاده مي كند كه با هر دستور خواندن و نوشتن بر روي فايل مقدار اين متغير به طور اتوماتيك تغيير مي كند، تا موقعيت فعلي فايل را مشخص نمايد. لذا عمل نوشتن بر روي فايل و عمل خواندن از روي آن، از جايي كه اين متغير نشان مي دهد، شروع مي شود.
۲ـ در هنگام خواندن داده ها از فايل بايد بتوان انتهاي فايل را تست نمود؛ يعني در برنامه بايد بتوان اين تست را انجام داد كه اگر در حين خواندن داده ها از فايل“ موقعيت سنج فايل” به انتهاي فايل رسيد دستور خواندن بعدي صادر نگردد؛ چرا كه در غير اين صورت، سيستم، پيام خطايي را مبني بر نبودن اطلاعات در فايل صادر مي‌كند.
در حين خواندن داده ها از فايل متني، پس از رسيدن به انتهاي فايل، تابع getc( ) ياfgetc() علامت EoF را بر مي گرداند. لذا در هنگام خواندن داده ها از فايل متني مي توان آنقدر به عمل خواندن ادامه داد تا اين كه كاراكتر خوانده شده برابر با EoF شود. روش ديگر براي تست كردن انتهاي فايل استفاده از تابع feof( ) است. الگوي اين تابع به صورت زير است:
int feof(FILE *fp)
در الگوي فوق،fp اشاره گري است كه مشخص مي كند اين تابع بايد بر روي چه فايلي عمل كند. تابع feof( ) بر تشخيص انتهاي فايل هاي بانيري و متني استفاده مي شود. اگر اشاره گر فايلي كه feof( ) به آن اشاره مي كند به انتهاي فايل رسيده باشد اين تابع ارزش درستي وگرنه ارزش نادرستي را بر مي گرداند.
ورودي ـ خروجي رشته ها
براي نوشتن رشته ها در فايل از تابعFputs( ) و براي خواندن رشته ها از فايل، از تابع Fgets( ) استفاده مي گردد. الگوي اين دو تابع به صورت زير مي باشد:
int Fputs(const char*str FILE* fp)
char* Fgets(char*str,int length,FILE*fp)
در الگوي فوق،fp اشاره گري است كه مشخص مي كند اين توابع بايد بر روي چند و چه فايلهايي عمل كنند در تابعfgets( ) اشاره گر str به رشته أي اشاره مي كند كه بايد در فايل نوشته شود. اين اشاره گر در تابعfputs( ) به رشته أي كه اطلاعات خوانده شده از فايل در آن قرار مي گيرند، اشاره مي كند.
length طول رشته أي را كه بايد از فايل خوانده شود مشخص مي كند. نحوه عمل تابعFgets( ) به اين صورت است كه: از ابتداي فايل شروع به خواندن مي كند تا به انتهاي يك خط برسد و يا رشته أي به طول length كاراكتر را از فايل بخواند. برخلاف تابعgets( ) در تابع Fgets( ) كاراكتري كه انتهاي خط را مشخص مي كند جزء رشته أي خواهدبود كه اين تابع از فايل مي خواند.
فايل به عنوان وسيله ورودي ـ خروجي
در مثالهايي كه تاكنون مطرح شده اند، فايل يا فقط به عنوان وسيله ورودي استفاده گرديده و يا فقط به عنوان وسيله خروجي. در اين قسمت مشاهده خواهد شد كه چگونه مي توان يك فايل را هم به عنوان وسيلة ورودي و هم به عنوان وسيلة خروجي مورد استفاده قرار داد؛ براي اين منظور كافي است در تابعFopen( ) به جاي mode از يكي از عبارات r + يا r +t ( باز كردن فايل متني موجود به عنوان ورودي، خروجي)w + ياw+t ( ايجاد يك فايل متني به عنوان ورودي ، خروجي) و يا a+b ( ايجاد و يا باز كردن فايل موجود بانيري به عنوان ورودي، خروجي) استفاده نمود به عنوان مثال دستورات زير را در نظر بگيريد:
Fp1=Fopen(“test.dat”,”w+b”); (۱)
Fp2=Fopen(“sample .dat”,”r+b”); (۲)
Fp3=Fopen(“test 2.dat”,”a+t”); (۳)
دستور او فايلي به نام test.dat را از نوع بانيري و به صورت ورودي و خروجي باز مي كند كه اشاره گرFp1 به آن اشاره مي كند. اگر فايل test.dat قبلاً وجود داشته باشد محتويات قبلي آن از بين خواهند رفت. دستور (۲) فايلي به نام sample.dat را كه اكنون بر روي درايو جاري وجود دارد و از نوع بانيري و به صورت ورودي و خروجي باز مي كند اگر فايل sample.dat بر روي درايو جاري وجود نداشته باشد، فايل باز نخواهد شد. دستور (۳) فايلي به نام test2.dat را از نوع متني و به صورت ورودي و خروجي باز مي كند. اگر فايلtest2.dat قبلاً وجود نداشته باشد ايجاد خواهد شد و اگر وجود داشته باشد اطلاعات قبلي آن محفوظ بوده، اطلاعات جديد به انتهاي آن اضافه خواهد شد.

در حين كار با فايل ها( نوشتن اطلاعات بر روي آنها و يا خواندن اطلاعات از آنها) براي برگشت به ابتداي فايل( تغيير“ موقعيت سنج فايل”) به طوري كه به ابتداي فايل اشاره مي كند. بايد فايل را بسته و مجدداً آن را باز نمود.(البته با توجه به مطالبي كه تاكنون در مورد فايل ها گفته شد.) اين مطلب در مثالهايي كه تاكنون مطرح شد به چشم مي خورد. اصلاً شايد در فايلهايي كه فقط به عنوان خروجي و يا فقط به عنوان ورودي باز مي شوند، نياز به برگشت به ابتداي فايل( بدون بستن و باز كردن مجدد آن) احساس نشود. ولي اين امر در مورد فايل هايي ورودي و خروجي به عنوان يك نياز مطرح است. براي اين منظور، از تابعي به نامrewind( ) استفاده مي گردد. الگوي تابعrewind( ) در فايل stdio.h قرار داشته و به صورت زير است:
void rewind(FILE * Fp)

در الگوي فوق Fp به فايلي اشاره مي كند كه “ موقعيت سنج” آن بايد به ابتداي فايل اشاره نمايد.
عيب يابي در ورودي ـ خروجي فايل

در حين انجام كار با فايلها ممكن است خطايي رخ دهد. به عنوان مثال، عدم وجود فضاي كافي براي ايجاد فايل آماده نبودن دستگاهي كه فايل بايد در آنجا تشكيل گردد و يا مواردي از اين قبيل منجر به بروز خطا مي شود. با استفاده از تابعFerror( ) مي‌توان از بروز خطا مطلع گرديد. الگوي تابعFerror( ) در فايل stdio.h قرار داشته به صورت زير است:

int Ferror (FILE *Fp)
در اين الگوFp اشاره گري است كه مشخص مي كند تابع بايد بر روي چه فايلي عمل كند. اين تابع منطقي است؛ بدين معني كه اگر خطايي در رابطه با فايلها رخ دهد ارزش“ درستي” و گرنه ارزش“ نادرستي” را بر مي گرداند. براي تشخيص خطا در كار با فايل ها، بلافاصله پس از هر عملي كه روي فايل انجام مي شود بايد از اين تابع استفاده نمود.

حذف فايل
براي حذف فايل هاي غير ضروري مي توان از تابع remove( ) استفاده كرد. الگوي اين تابع در فايل stdio.h قرار داشته به صورت زير است:
int remove(char * Filename)

در الگوي فوقFilename به نام فايلي كه بايد حذف شود اشاره مي كند اگر عمل تابع با موقعيت انجام شود مقدار صفر و گرنه مقداري غير از صفر برگردانده خواهد شد.
بافر(buffer)

بافر، حافظه أي است كه به فايل ها اختصاص مي يابد تا اعمال ورودي ـ خروجي بر روي آنها با سرعت بيشتري انجام گيرد در حين خروج از برنامه خوب است جهت اطمينان بيشتر، به ماشين دستور داد تا كلية داده هاي موجود در بافرها را به فايل مربوطه منتقل نمايد. براي اين منظور مي توان از تابع Fflush( ) استفاده نمود. اگر كار اين تابع با موفقيت انجام شود مقداري كه توسط آن برگردانده مي شود برابر با صفر و گرنه برابر با EoF خواهد بود(EoF ماكرويي است كه در فايل stdio تعريف شده است) الگوي تابع Fflush در فايلstdio.h قرار داشته و به صورت زير است:
int Fflush(FILE *Fp)

در الگوي فوق Fp فايلي است كه مشخص مي كند كه تابع Fflush بايد بر روي آن
عمل نمايد. اگرFp ذكر نشود تابع Fflush بر روي كليه فايلهايي كه به عنوان خروجي باز شده اند، عمل مي كند به عنوان مثال دستور Fflush كليه بافر هاي مربوط به فايل ي با اشاره گر F را در اين فايل مي نويسد.