Բաժին 6.1
Մուտք/Ելք
ֆայլերի հետ
C++ը մեզ հնարավորություն է տալիս ֆայլերի հետ մուտք/ելք կատարել՝ օգտագործելով հետևյալ կլասերը.
· ofstream՝ Ֆայլերի մեջ գրելու համար (ժառանգված է ostream-ից)
· ifstream՝ Ֆայլերից կարդալու համար (ժառանգված է istream-ից)
· fstream ՝ և՛ գրելու, և՛ կարդալու համար (ժառանգված է iostream-ից)
Այս կլասերի օբյեկտների հետ սովորաբար առաջինը կատարվող գործողությունը այն կապելն է որևէ իրական ֆայլի հետ. այլ խոսքով ասած՝ ֆայլ բացելը: Բացված ֆայլը ներկայացվում է որպես հոսքի օբյեկտ (ինչպես cout-ը և cin-ը), և այդ հոսքի հետ կատարվող ցանկացած մուտք/ելք կատարվում է նաև ֆայլի հետ:
Որպեսզի որևէ ֆայլ բացել հոսքի օբյեկտից, օգտագործում ենք նրա անդամ open() ֆունկցիան.
void open (const char * ֆայլի անուն, openmode բացման ձև);
որտեղ ֆայլի անունը սիմվոլային տող է, որը ներկայացնում է ֆայլի անունը և, անհրաժեշտության դեպքում, հասցեն (“C:\file.txt”): Իսկ բացման ձևը հետևյալ դրոշակների կոմբինացիա է՝
|
ios::in |
Ֆայլը բացել կարդալու համար |
|
ios::out |
Ֆայլը բացել գրելու համար |
|
ios::ate |
Սկզբնական դիրքը՝ ֆայլի վերջում |
|
ios::app |
Բոլոր փոփոխությունները գրվում են սկսած ֆայլի վերջից |
|
ios::trunc |
Եթե ֆայլը գոյություն ունի, այն մաքրվում է |
|
ios::binary |
Երկուական ռեժիմ |
Այս դրոշակները կարելի է կոմբինացնել (միանգամից ընտրել մի քանի հատը)՝ օգտագործելով բիթային ԿԱՄ օպերատորը (|): Օրինակ՝ եթե մենք ուզում ենք բացել "orinak.bin" ֆայլը և նրա մեջ ինֆորմացիա գրել երկուական ռեժիմում, ապա պետք է կանչենք open ֆունկցիան՝ հետևյալ ձևով.
ofstream file;
file.open ("orinak.bin", ios::out | ios::app | ios::binary);
Բոլոր երեք կլասերի (ofstream, ifstream and fstream ) անդամ open ֆունկցիաները ունեն լռության բացման ձև: Կլասերից յուրաքանչյուրի համար այն յուրահատուկ է.
|
կլաս |
լռությամբ բացման ձև |
|
ofstream |
ios::out | ios::trunc |
|
ifstream |
ios::in |
|
fstream |
ios::in | ios::out |
Լռության արժեքը օգտագործվում է միայն այն դեպքում, երբ open ֆունկցիան կանչելիս չի նշվել բացման ձև. հակառակ դեպքում լռության արժեքը անտեսվում է:
Ինչպես ասացինք, առաջին գործողությունը, որ արվում է ofstream, ifstream և fstream կլասերի օբյեկտների հետ, ֆայլ բացելն է. այդ պատճառով այս կլասերը ունեն կոնստրուկտոր, որը միանգամից կանչում է open անդամ-ֆունկցիան: Այս ձևով մենք կարող էինք հայտարարել նախորդ օբյեկտը՝ պարզապես գրելով
ofstream file ("orinak.bin", ios::out | ios::app | ios::binary);
Երկու եղանակն էլ կունենան նույն ազդեցությունը:
Դուք կարող եք ստուգել՝ արդյոք ֆայլի բացման պրոցեսը նորմալ է անցել՝ օգտագործելով is_open() անդամ-ֆունկցիան.
bool is_open();
Սա վերադարձնում է բուլեան տիպ՝ true, եթե օբյեկտը նորմալ կապվել է ֆայլի հետ, իսկ հակառակ դեպքում՝ false:
Ֆայլը բացելուց և նրա հետ աշխատելուց հետո այն պետք է փակել, որպեսզի այն կրկին հասանելի դառնա մյուս ծրագրերի համար: Դա անելու համար պետք է կանչել close() անդամ-ֆունկցիան, որը ավարտում է ֆայլի հետ աշխատանքը և փակում ֆայլը: Դրա կանչը շատ հեշտ է.
void close ();
Այս ֆունկցիան կանչելուց հետո հոսքի օբյեկտը կարելի է օգտագործել այլ ֆայլեր բացելու համար, իսկ փակված ֆայլը դառնում է այլ ծրագրերի համար հասանելի:
Եթե հոսքի օբյեկտը ոչնչացվում է (օրինակ՝ եթե ծրագիրն ավարտվում է), իսկ ֆայլը դեռ բաց է, դեստրուկտորը ավտոմատաբար կանչում է close անդամ-ֆունկցիան:
Ֆայլերի հետ աշխատանք տեքստային ռեժիմում
ofstream, ifstream և fstream կլասերը համապատասխանաբար ժառանգված են ostream, istream և iostream դասերից: Դրա շնորհիվ՝ մենք կարող ենք fstream օբյեկտների հետ աշխատել ծնող դասերի անդամ-ֆունկցիաներով:
Տեքստային ռեժիմում ֆայլերի հետ աշխատելիս մենք ofstream, ifstream և fstream կլասերի օբյեկտների հետ կաշխատենք, ինչպես cin-ի և cout-ի հետ: Ստորև բերված օրինակում մենք օգտագործում ենք << օպերատորը.
// grenq textayin file-i mech #include <fstream.h> int main () { ofstream orinakfile ("orinak.txt"); if (orinakfile.is_open()) {orinakfile << "Sa mi tox e.\n"; orinakfile << "Sa mek ayl tox e.\n"; orinakfile.close(); } return 0; } |
|
Sa mi tox e. |
Ինֆորմացիայի մուտքը կազմակերպում ենք ճիշտ այնպես, ինչպես cin -ի հետ.
// kardanq textayin file #include <iostream.h> #include <fstream.h> #include <stdlib.h> int main () {char buffer[256]; ifstream orinakfile ("example.txt");if (! orinakfile.is_open()) { cout << "Sxal file-@ bacelis"; exit (1); }while (! orinakfile.eof() ) {orinakfile.getline (buffer,100); cout << buffer << endl; } return 0; } |
|
Sa mi tox e. |
Այս օրինակը կարդում է տեքստային ֆայլը և նրա պարունակությունը տպում էկրանի վրա: Այստեղ մենք օգտագործեցինք մի նոր անդամ-ֆունկցիա՝ eof: Այս ֆունկցիան ifstream-ը ժառանգել է ios կլասից: Սա վերադարձնում է true, եթե հասել է ֆայլի վերջին:
Բացի eof()-ից կան նաև այլ անդամ-ֆունկցիաներ, որոնց միջոցով կարելի է տեղեկանալ հոսքի վիճակի մասին (այս բոլոր ֆունկցիաները վերադարձնու են bool արժեք).
bad()
Վերադարձնում է true, եթե ֆայլը կարդալուց կամ գրելուց որևէ պրոբլեմ է առաջացել: Օրինակ՝ եթե ֆայլը բացված է միայն կարդալու համար, իսկ մենք գրելու փորձ ենք կատարում, կամ եթե այն սարքը, որի վրա ուզում ենք գրել, ամբողջովին զբաղված է կամ գրելուց պաշտպանված:
fail()
Վերադարձնում է true բոլոր այն դեպքերում, երբ true է վերադարձնում bad()-ը, և այն դեպքերում, երբ առաջանում է ինֆորմացիայի ֆորմատավորման սխալ (օր.՝ ծրագիրը փորձում է որևէ թիվ կարդալ, իսկ ստանում է տեքստ):
eof()
Վերադարձնում է true, երբ կարդացման համար բացված ֆայլը հասել է վերջին (այլևս կարդալու սիմվոլ չկա):
good()
Վերադարձնում է false բոլոր այն դեպքերում, երբ նախորդներից որևէ մեկը կվերադարձներ true:
get և put հոսքային ցուցիչներ
Բոլոր մուտքի-ելքի օբյեկտները ունեն գոնե մեկ հոսքային ցուցիչ:
Այս ցուցիչները կարող ենք օգտագործել հետևյալ անդամ-ֆունկցիաների միջոցով.
tellg() և tellp()
Այս երկու ֆունկցիաները արգումենտներ չեն պահանջում և վերադարձնում են pos_type տիպի արժեք, որը ամբողջ թիվ է և իրենից ներկայացնում է get հոսքային ցուցիչի ներկա դիրքը (tellg-ի դեպքում) կամ put հոսքային ցուցիչի ներկա դիրքը (tellp-ի դեպքում):
seekg() և seekp()
Սրանք օգտագործվում են get և put հոսքային ցուցիչների դիրքը փոխելու համար: Երկուսն ել գերբեռնված են երկու տարբեր նախատիպերով.
seekg ( pos_type դիրք );
seekp ( pos_type դիրք );
Այս դեպքում տալիս ենք ցուցիչի դիրքը՝ հաշված ֆայլի սկզբից: դիրքը պետք է ունենա նույն տիպը՝ ինչ վերադարձվում է tellg և tellp անդամ-ֆունկցիաների կողմից:
seekg (
off_type դիրք, seekdir ուղղություն );
seekp ( off_type դիրք, seekdir ուղղություն );
Այս ֆունկցիաները օգտագործելիս կարող ենք նշել, թե որտեղից հաշվել տրված դիրքը: ուղղությունը կարող է լինել հետևյալներից որևէ մեկը.
|
ios::beg |
դիրքը հաշված հոսքի (ֆայլի) սկզբից |
|
ios::cur |
դիրքը հաշված ցուցիչի ներկա դիրքից |
|
ios::end |
դիրքը հաշված հոսքի վերջից |
Ե՛վ get, և՛ put ցուցիչների արժեքները տեքստային ֆայլերի համար և երկուական ֆայլերի համար հաշվվում են տարբեր ձևի (դա հանդիսանում է այն բանի հետևանք, որ տեքստային ֆայլերի հետ աշխատանքի ժամանակ անտեսվում են որոշ հատուկ սիմվոլներ): Այս պատճառով խորհուրդ է տրվում օգտագործել tellg և tellp ֆունկցիաների միայն առաջին նախատիպերը: Երկուական ֆայլերի հետ կարեի է օգտագործել երկու նախատիպներն էլ:
Հաջորդ օրինակը օգտագործում է այս ֆունկցիաները, որպեսզի որոշել երկուական ֆայլի չափը:
// obtaining file size #include <iostream.h> #include <fstream.h> const char * filename = "orinak.txt"; int main () { long l,m; ifstream file (filename, ios::in|ios::binary); l = file.tellg(); file.seekg (0, ios::end); m = file.tellg(); file.close(); cout << filename << "-i chap@ "; cout << (m-l) << " byte e.\n"; return 0;} |
|
orinak.txt-i chap@ 33 bytes e. |
Երկուական ֆայլերի մեջ ինֆորմացիայի մուտքը/ելքը << և >> օպերատորների ինչպես նաև getline ֆունկցիայի միջոցով իմաստալից չէ, սակայն դրանք լիովին թույլատրելի գործողություններ են:
Հոսքերը ունեն երկու հատուկ ֆունկցիաներ մուտքի/ելքի համար. դրանք են՝ write և read: Դրանցից առաջինը (write) ostream կլասի անդամ-ֆունկցիա է և ժառանգված է ofstream-ի կողմից, իսկ read-ը istream կլասի անդամ է և ժառանգված է ifstream-ի կողմից: fstream կլասի օբյեկտները ունեն և՛ write, և՛ read ֆունկցիաները: Այդ ֆունկցիաների նախատիպերը հետևյալն են:
write ( char * buffer, streamsize չափ );
read ( char * buffer, streamsize չափ );
Որտեղ buffer -ը հիշողության հասցե է, որտեղ գրվում է կարդացված ինֆորմացիան, և որտեղից կարդացվում է գրվելիք ինֆորմացիան: Իսկ չափ արգումենտը ամբողջ թիվ է, որը ներկայացնում է buffer-ից(ում) կարդացվելիք/գրվելիք սիմվոլների քանակը:
// kardum enq erkuakan file #include <iostream.h> #include <fstream.h> const char * filename = "example.txt"; int main () { char *buffer; long size; ifstream file (filename,ios::in|ios::binary|ios::ate); size = file.tellg(); file.seekg (0,ios::beg); buffer = new char [size]; file.read (buffer,size);file.close(); cout << "ayjm file-@ amboxchovin gtnvum e buffer-um";delete[] buffer; return 0; } |
|
ayjm file-@ amboxchovin gtnvum e buffer-um |
Բուֆերներ և Սինխրոնիզացիա
Ֆայլային հոսքերը կապված են streambuf տիպի buffer-ի հետ: buffer-ը հիշողության բլոկ է, որը աշխատում է որպես միջնորդ` հոսքի և ֆիզիկական ֆայլի միջև: Օրինակ՝ ելքի հոսքի դեպքում, ամեն անգամ, put անդամ-ֆունկցիան կանչելիս (մի սիմվոլ գրելու համար) սիմվոլը միանգամից չի գրվում ֆայլի մեջ. փոխարենը այն տեղադրվում է buffer-ի մեջ:
Երբ բուֆերը դատարկվում է (flush) նրա պարունակությունը գրվում է ֆայլի մեջ (եթե դա ելքի հոսք է), կամ ջնջվում է (մուտքի հոսքի դեպքում): Այս պրոցեսը կոչվում է սինխրոնիզացիա (synchronization) և տեղի է ունենում հետևյալ դեպքերում.
· Երբ ֆայլը փակվում է. ֆայլը փակելուց առաջ բոլոր բուֆերները սինխրոնիզացվում են:
· Երբ բուֆերը լցվում է. բուֆերները ունեն որոշակի չափեր, և երբ բուֆերը ամբողջովին լցվում է այն սինխրոնիզացվում է:
· Հատուկ դեպքերում. flush և endl. ազդակները օգտագործելիս բուֆերը սինխրոնիզացվում է:
· sync() ֆունկցիայի կանչի դեպքում. sync() (արգումենտներ չկան) անդամ-ֆունկցիայի կանչը բերում է անմիջապես սինխրոնիզացիայի: Այս ֆունկցիան վերադարձնում է int տիպի արժեք, որը հավասար է (-1)-ի, եթե հոսքին ոչ մի բուֆեր կապած չէ կամ եթե որևէ պրոբլեմ է առաջացել:
Նախորդը