Բաժին 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;
}

file orinak.txt

Sa mi tox e.
Sa mek ayl 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.
Sa mek ayl 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: Դրանցից առաջինը (writeostream կլասի անդամ-ֆունկցիա է և ժառանգված է ofstream-ի կողմից, իսկ readistream կլասի անդամ է և ժառանգված է 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)-ի, եթե հոսքին ոչ մի բուֆեր կապած չէ կամ եթե որևէ պրոբլեմ է առաջացել:

Նախորդը