This is an old revision of the document!


Laboratorul 11. Operatii cu fişiere. Aplicaţii folosind fişiere.

Responsabil:

Obiective

În urma parcurgerii acestui laborator studentul va fi capabil să:

  • lucreze cu fişiere text (deschidere, închidere, citire, scriere)
  • înteleaga un fişier binar şi să lucreze cu el;
  • să se poziţioneze in interiorul unui fişier;
  • poată determina poziţia în cadrul unui fişier;
  • înteleagă diferenţa între organizarea internă a fişierelor pe sistemele de operare Linux şi Windows.

Noţiuni teoretice

Introducere

Un fişier este o structură dinamică, situată în memoria secundară (pe disk-uri). Limbajul C permite operarea cu fişiere:

  • de tip text - un astfel de fişier conţine o succesiune de linii, separate prin NL ('\n')
  • de tip binar - un astfel de fişier conţine o succesiune de octeti, fără nici o structură.

Prelucrarea unui fişier presupune asocierea acestuia cu un canal de I/E (numit flux sau stream). Există trei canale predefinite, care se deschid automat la lansarea unui program:

  • stdin - fişier de intrare, text, este intrarea standard - tastatura
  • stdout - fişier de iesire, text, este ieşirea standard - ecranul monitorului.
  • stderr – fişier de iesire, text, este ieşirea standard unde sunt scris mesajele de eroare - ecran.

Pentru a prelucra un fişier, trebuie parcurse următoarele etape:

  • se defineşte o variabilă de tip FILE * pentru accesarea fişierului; FILE * este un tip structură definit în stdio.h, care conţine informaţii referitoare la fişier şi la tamponul de transfer de date între memoria centrală şi fişier (adresa, lungimea tamponului, modul de utilizare a fişierului, indicator de sfârsit, de poziţie în fişier)
  • se deschide fişierul pentru un anumit mod de acces, folosind funcţia de bibliotecă fopen, care realizează şi asocierea între variabila fişier şi numele extern al fişierului
  • se prelucrează fişierul în citire/scriere cu funcţiile specifice
  • se inchide fişierul folosind funcţia de bibliotecă fclose.

Mai jos se prezintă restul funcţiilor de prelucrare a fişierelor:

FILE *fopen(const char *nume_fis, const char *mod);

deschide fişierul cu numele dat pentru acces de tip mod.

Returnează pointer la fişier sau NULL dacă fişierul nu poate fi deschis; valoarea returnată este memorată în variabila fişier, care a fost declarată pentru accesarea lui.

Modul de deschidere poate fi:

  • “r” - readonly , este permisă doar citirea dintr-un fişier existent
  • “w” - write, crează un nou fişier, sau dacă există deja, distruge vechiul continut
  • “a” - append, deschide pentru scriere un fişier existent ( scrierea se va face în continuarea

informaţiei deja existente în fişier, deci pointerul de acces se plasează la sfârşitul fişierului )

  • ”+” - permite scrierea şi citirea - actualizare (ex: “r+”, “w+”, “a+”). O citire nu poate fi direct urmată

de o scriere şi reciproc. Întâi trebuie repoziţionat cursorul de acces printr-un apel la fseek.

  • “b” - specifică fişier de tip binar
  • “t” - specifică fişier de tip text (implicit), la care se face automat conversia CR-LF(“\n\f”) în sau din CR ('\n').
int fclose(FILE *fp);

închide fişierul şi eliberează zona tampon; returnează 0 la succes, EOF la eroare

int fseek(FILE *fp, long offset, int whence);

repoziţionează pointerul asociat unui fişier . Offset - numărul de octeţi între poziţia dată de whence şi noua poziţie.

whence - are una din cele trei valori posibile:

  • SEEK_SET = 0 - Căutarea se face de la începutul fişierului
  • SEEK_CUR = 1 - Căutare din poziţia curentă
  • SEEK_END = 2 - Căutare de la sfârşitul fişierului
int ftell(FILE *fp);

întoarce poziţia curentă în cadrul lui fp

int fgetpos(FILE *fp, fpos_t *ptr);

această funcţie memorează în variabila fptr poziţia curentă în cadrul fişierului fp (ptr va putea fi folosit ulterior cu funcţia fsetpos).

int fsetpos(FILE *fp, const fpos_t *ptr);

această funcţie setează poziţia curentă în fişierul fp la valoarea ptr, obţinută anterior prin funcţia fgetpos.

int feof(FILE *fis);

returnează 0 dacă nu s-a detectat sfârşit de fişier la ultima operaţie de citire, respectiv o valoare nenulă (adevărată) pentru sfârşit de fişier.

FILE* freopen(const char *filename, const char *mode, FILE *fp);

se închide fişierul fp, se deschide fişierul cu numele filename în modul mode şi acesta se asociază la fp; se întoarce fp sau NULL în caz de eroare.

int fflush(FILE *fp);

Această funcţie se utilizează pentru fişierele deschise pentru scriere şi are ca efect scrierea în fişier a datelor din bufferul asociat acestuia, care înca nu au fost puse în fişier.

Citirea şi scrierea în/din fişiere

Citirea/scrierea în fişiere se poate face în doua moduri (în functie de tipul fişierului): în mod text sau în mod binar. Principalele diferenţe dintre cele doua moduri sunt:

  • în modul text, la sfarsitul fişierului se pune un caracter suplimentar, care indica sfârşitul de fişier. În DOS şi Windows se utilizeaza caracterul cu codul ASCII 26 (Ctrl-Z), iar în Unix se utilizează caracterul cu codul ASCII 4. Dacă citim un fişier în mod text, citirea se va opri la intâlnirea acestui caracter, chiar dacă mai există şi alte caractere după el. În modul binar nu există caracter de sfârşit de fişier (mai precis, caracterul cu codul 26, respectiv 4, este tratat la fel ca şi celelalte caractere).
  • în DOS şi Windows, în modul text, sfârşitul de linie este reprezentat prin două caractere, CR (Carriage Return, cod ASCII 13) şi LF (Line Feed, cod ASCII 10). Atunci când în modul text scriem un caracter '\n' (LF) în fişier, acesta va fi convertit într-o secventă de 2 caractere CR şi LF. Când citim în mod text dintr-un fişier, secvenţa CR, LF este convertită într-un '\n' (LF). În Unix, sfârşitul de linie este reprezentat doar prin caracterul LF. În mod binar, atât în DOS-Windows cât şi în Unix, sfârşitul de linie este reprezentat doar prin caracterul LF.

Modul binar se utilizează de obicei pentru a scrie în fişier datele exact aşa cum sunt reprezentate în memorie (cu functiile fread, fwrite) - de exemplu pentru un număr intreg se va scrie reprezentarea internă a acestuia, pe 2 sau pe 4 octeti.

Modul text este utilizat mai ales pentru scrierea cu format (cu funcţiile fprintf, fscanf) - în cazul acesta pentru un număr întreg se vor scrie caracterele ASCII utilizate pentru a reprezenta cifrele acestuia (adică un şir de caractere cum ar fi “1” sau “542”).

Citire/scriere cu format

int fprintf(FILE *fp, const char *format, ...);
int fscanf(FILE *fp, const char *format, ...);

Funcţiile sunt utilizate pentru citire/scriere în mod text şi sunt asemănătoare cu printf/scanf (diferenţa fiind că trebuie dat pointerul la fişier ca prim parametru).

Citire/scriere la nivel de caracter

int fgetc(FILE *fp); // întoarce următorul caracter din fişier, EOF la sfârşit de fişier
char* fgets(char *s, int n, FILE *fp); // întoarce următoarele n caractere de la pointer sau pâna la sfârşitul de linie
int fputc(int c, FILE *fp); //pune caracterul c in fişier
int ungetc(int c, FILE *fp); // pune c în bufferul asociat lui fp (c va fi următorul caracter citit din fp)

Citire/scriere fără conversie

size_t fread(void *ptr, size_t size, size_t nrec, FILE *fp);
size_t fwrite(const void *ptr, size_t size, size_t nrec, FILE *fp);

Cu aceste funcţii lucrăm cand deschidem fişierul în mod binar; citirea/scrierea se face fără nici un fel de conversie sau interpretare. Se lucrează cu “înregistrări”, adică zone compacte de memorie: funcţia fread citeşte nrec înregistrări începănd de la poziţia curentă din fişierul fp, o înregistrare având dimensiunea size. Acestea sunt depuse în tabloul ptr. “Înregistrările” pot fi asociate cu structurile din C - adică în mod uzual, tabloul ptr este un tablou de structuri (dar în loc de structuri putem avea şi tipuri simple de date).

Exerciţii de Laborator

  1. [2p] Ştergeţi toate apariţiile unui cuvânt dintr-un fişier text. Numele fișierului și cuvântul care se şterge se citesc de la tastatură. Programul vostru trebuie să suprascrie fișierul inițial.
  2. Rezolvaţi următoarele cerinţe:
    1. [2p] Să se scrie un program pentru crearea unui fişier binar, având articole structuri cu următoarele câmpuri:
       nume depunător
          şir de maxim 30 de caractere
       data depunerii
          o structură având câmpurile întregi: zi,lună,an
       suma depusă 
          o valoare reala. 
        Observaţie: Articolele sunt grupate pe zile in ordine cronologică.
      Datele se introduc de la consolă, fiecare pe 3 linii. 
    2. [1p] Citiţi din fişierul creat la punctul a şi afişati rezultatele intr-un fişier text, a cărui denumire se va citi de la tastatură.
  3. [2p] Generati un fisier binar care sa contina un numar n de numere intregi. n se va citi de la tastatura si cele n numere se vor genera random. In fisierul de output afisati doar cele n numere intregi generate. Numele fisierului generat se va citi de asemenea de la tastatura.
  4. Se citeste de la tastatura numele unui fisier binar. In cadrul acestuia sunt un numar nedeterminat de numere intregi.
    1. [1p] Afisati numarul de numere intregi din acest fisier.
          Indicatie:
      fseek(file,0,SEEK_END);
      poz=ftell(file);
      nrNumereIntregi=poz/?;
    2. [1p] Să se calculeze suma numerelor din fişier .
    3. [1p] Să se calculeze suma numerelor impare din fişier .
    4. [1p] Să se calculeze suma numerelor prime din fişier .

Pentru acest exercitiu puteti sa utilizati ca fisier de input fisierul generat la exercitiul anterior.

Bonus

  1. [3p] Să se scrie un program care determină toate secvenţele binare de lungime n, fiecare din ele conţinând nu mai mult de k cifre de 1.
    1. Intrare: Numerele naturale n, 1<n<20, şi k, k⇐n, se citesc din fişierul in.txt.
    2. Ieşire: fiecare linie a fişierului text out.txt va conţine câte o secvenţă binară distinctă, ce corespunde condiţiilor din enunţul problemei.
  2. [2p] Într-un fişier există cuvinte, câte unul pe fiecare rând. Să se verifice dacă cuvintele de pe poziţii consecutive sunt rime. (dacă ultimele p caractere ale celor 2 cuvinte coincid, unde p este prima valoare citită din acelaşi fişier).
rime.in
    2
    ferit
    indraznit
    indraznet
    istet
    descurcaret
rime.out
    DA
    NU
    DA
    DA
  Explicaţie: 
    Ultimele 2 litere ale cuvintelor "ferit" si "indraznit"
coincid, pe când "indraznit" cu "indraznet" nu coincid.

Arhiva laborator

Referinţe

programare-ca/laboratoare/lab11.1355723946.txt.gz · Last modified: 2012/12/17 07:59 by emil.racec
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0