C++ Lucru cu fișiere

Rezumatul de mai jos este extras din:

Programele lucrează cu un volum mare de date. Stocarea acestora se face pe diverse suporturi (hard disk, stick USB, etc.) sub formă de fişiere.

Până la citirea acestei pagini ați lucrat cu două tipuri speciale de fişiere text şi anume cu cele ale căror nume logice sunt cin şi cout. Am spus speciale pentru că ele nu sunt memorate pe suport extern, ci corespund dispozitivelor standard de intrare (stdin standard input), respectiv ieşire (stdout, standard output) , dar, în rest, au aceleaşi caracteristici.

Pentru a putea fi prelucrat, orice fişier are două nume:

  • Numele logic este cel folosit în program pentru referirea fişierului.
  • Numele fizic este cel sub care fişierul se găseşte memorat pe suportul extern. El poate conţine şi calea - subdirectorul în care se găseşte (altfel, fişierul se consideră plasat în directorul curent)

Un fişier text se termină întotdeauna cu caracterul EOF. Acesta permite ca la prelucrare să poată fi identificat sfârşitul fişierului

Fişierul text se consideră alcătuit din una sau mai multe linii. O linie, mai puţin ultima, se termină prin caracterul newline (\n).

O variabilă specială, numită pointer reţine întotdeauna un octet al fişierului. Acesta este primul care va fi prelucrat - citit sau scris. După cum vedeţi în figură, ne imaginăm pointerul ca o săgetuţă care marchează octetul. În exemplu, aceasta marchează al treilea octet al şirului, adică cel de indice 2.

pointer-fisier

Pentru problemele de informatică de liceu, în general se recomandă folosirea clasei de stream fstream din C++ care e folosita atât pentru citire cât și pentru scriere:

fstream nume_logic(char* nume_fizic, int mod_de_deschidere);

Pentru parametrul mod_de_deschidere avem următoarele valori posibile:

mod_de_deschidere Semnificație
ios::in Open for input operations.
ios::out Open for output operations.
ios::binary Open in binary mode.
ios::ate Set the initial position at the end of the file. If this flag is not set, the initial position is the beginning of the file.
ios::app All output operations are performed at the end of the file, appending the content to the current content of the file.
ios::trunc If the file is opened for output operations and it already existed, its previous content is deleted and replaced by the new one.

Modurile de mai sus se pot combina folosind operatorul SAU (|) exemplu:

fstream myfile("example.txt", ios::out | ios::app | ios::binary);

Pentru stream-uri de intare, respectiv de ieșire se pot folosi, în loc de fstream:

ifstream("example.txt"); //pentru stream date de intrare (citire date)
ofstream("example.txt"); //pentru stream date de iesire (afisare date)

Alte exemple:

Declar un fişier text care se va găsi în rădăcină, cu numele fizic fis.txt. Fişierul a fost declarat în vederea creării lui. În eventualitatea că în rădăcină se mai găseşte un fişier cu acest nume, acesta din urmă va fi distrus. Numele său logic este f.

fstream f("c:\\fis.txt", ios::out);
//sau
ofstream f("c:\\fis.txt");

Declar un fişier text cu numele fizic date.txt şi numele logic g. Fişierul a fost declarat în vederea citirii (consultării), deci el trebuie să existe pe suport. Întrucât nu a fost precizată calea, acesta trebuie să se găsească în directorul curent.

fstream g("date.txt", ios::in);
//sau
ifstream f("date.txt");

Cum știu că am ajuns la sfârșitul unui fișier? Pentru un stream definit există metoda ```eof`` care poate fi folosită ca în exemplul de mai jos:

#include <iostream>
#include <fstream>

using namespace std;

int main()
{
    ifstream fin("af.in");
    //alternativ: fstream fin("af.in", ios::in);

    char car;

    //citesc caracter cu caracter din fisierul af.in pana cand dau
    //de caracterul "end of file" -> EOF
    while (!fin.eof()) {
        fin >> car;
    }

    return 0;
}

Un exemplu complet de program care scrie un text într-un fișier:

#include <iostream>
#include <fstream>

using namespace std;

int main()
{
  fstream myfile("example.txt", ios::out);

  myfile << "Writing this to a file.\n";

  myfile.close();

  return 0;
}

Exemplul de mai sus, care scrie un text într-un fișier, se putea scrie și:

#include <iostream>
#include <fstream>

using namespace std;

int main()
{
  ofstream myfile("example.txt");

  myfile << "Writing this to a file.\n";

  myfile.close();

  return 0;
}

Un alt exemplu: Se citesc 2 numere din sum.in si un nr de la tastatura. Afisati suma lor (celor 3) in fisierul sum.out

#include <iostream>
#include <fstream>

using namespace std;

int main()
{
    //imi definesc stream de date de intrare

    ifstream fin("sum.in");
    //alternativ este: fstream fin("sum.in", ios::in);

    //imi definesc stream de date de iesire

    ofstream fout("sum.out");
    //alternativ este: fstream fout("sum.out", ios::out);

    int a, b, x, s;

    fin >> a >> b;
    cin >> x;

    fin.close();

    s = a + b + x;

    fout << s << endl;
    fout.close();

    return 0;
}

Un alt exemplu: rezolvare parțială a problemei https://www.pbinfo.ro/probleme/2641/af Atenție la tipul de date ales pentru variabilele semn, egal

#include <iostream>
#include <fstream>

using namespace std;

int main()
{
    fstream af("af.in", ios::in);

    int n, nr1, nr2, rez;
    char semn, egal;

    af >> n;

    cout << n << endl;

    for (int i = 0; i < n; i++) {
        af >> nr1 >> semn >> nr2 >> egal >> rez;
        cout << nr1 << " " << semn << " " << nr2 << endl;
    }

    af.close();

    return 0;
}