Contacte

Lucrul cu datele dintr-un fișier c. Lucrul cu fișiere text. Citirea și scrierea dintr-un fișier binar

Funcția I / O a fișierelor în C ++ este aproape la fel ca I / O normală (dar cu câteva nuanțe).

Clasa I / O fișier

Există cele trei clase principale de fișiere I / O în C ++:

ofstream(este un copil al clasei);

fstream(este un copil din clasa iostream).

Puteți utiliza aceste clase pentru a efectua introducerea unidirecțională a fișierelor, ieșirea unidirecțională a fișierelor și I / O a fișierelor bidirecționale. Pentru a le utiliza, trebuie doar să vă conectați fstream.

Spre deosebire de fluxurile cout, cin, cerr și clog, care pot fi utilizate imediat, fluxurile de fișiere trebuie setate în mod explicit de către programator. Adică, pentru a deschide un fișier pentru citire și / sau scriere, trebuie să creați un obiect din clasa I / O a fișierului corespunzător, specificând numele fișierului ca parametru. Apoi, folosind operatorii de inserare (<<) или извлечения (>>), puteți scrie date într-un fișier sau citiți conținutul unui fișier. După aceea, finalul este - trebuie să închideți fișierul: sunați explicit metoda close () sau doar lăsați variabila I / O a fișierului să iasă din domeniul de aplicare (clasa I / O a fișierului va închide automat acest fișier pentru noi)

Ieșire fișier

Pentru a scrie într-un fișier, utilizați clasa de curent... De exemplu:

#include #include #include // pentru a utiliza exit () int main () (folosind spațiul de nume std; // ofstream este utilizat pentru a scrie date într-un fișier // Creați un fișier SomeText.txt ofstream outf („SomeText.txt”); // Dacă nu putem deschideți acest fișier pentru a scrie date în acesta dacă (! outf) (// Apoi afișați un mesaj de eroare și executați exit () cerr<< "Uh oh, SomeText.txt could not be opened for writing!" << endl; exit(1); } // Записываем в файл следующие две строчки outf << "See line #1!" << endl; outf << "See line #2!" << endl; return 0; // Когда outf выйдет из области видимости, то деструктор класса ofstream автоматически закроет наш файл }

#include

#include

#include // a folosi exit ()

int main ()

folosind spațiul de nume std;

// ofstream este folosit pentru a scrie date într-un fișier

// Creați un fișier SomeText.txt

ofstream outf ("SomeText.txt");

// Dacă nu putem deschide acest fișier pentru a scrie date pe acesta

dacă (! outf)

// Apoi afișăm un mesaj de eroare și executăm exit ()

cerr<< << endl ;

ieșire (1);

// Scrieți următoarele două rânduri în fișier

outf<< "See line #1!" << endl ;

outf<< "See line #2!" << endl ;

retur 0;

// Când outf iese din scop, destructorul clasei ofstream ne va închide automat fișierul

Dacă vă uitați în directorul de proiect ( Faceți clic dreapta pe fila cu numele fișierului dvs. .cpp în Visual Studio > "Deschideți folderul care conține"), veți vedea un fișier numit SomeText.txt care conține următoarele linii:

Vezi linia # 1!
Vezi linia # 2!

Vă rugăm să rețineți, putem folosi și metoda put () pentru a scrie un caracter într-un fișier.

Introducere fișier

#include #include #include #include // pentru a utiliza exit () int main () (folosind spațiul de nume std; // ifstream este utilizat pentru a citi conținutul fișierului // Încercați să citiți conținutul fișierului SomeText.txt ifstream inf („SomeText.txt”) ; // Dacă nu putem deschide acest fișier pentru a citi conținutul acestuia dacă (! Inf) (cerr<< "Uh oh, SomeText.txt could not be opened for reading!" << endl; exit(1); } // Пока есть данные, которые мы можем прочитать while (inf) { // То перемещаем эти данные в строку, которую затем выводим на экран string strInput; inf >> strInput; cout<< strInput << endl; } return 0; }

#include

#include

#include

#include // a folosi exit ()

int main ()

folosind spațiul de nume std;

// ifstream este folosit pentru a citi conținutul fișierului

// Dacă nu putem deschide acest fișier pentru a citi conținutul acestuia

dacă (! inf)

// Apoi afișăm următorul mesaj de eroare și executăm exit ()

cerr<< << endl ;

ieșire (1);

// În timp ce există date pe care le putem citi

în timp ce (inf)

// Apoi mutăm aceste date într-o linie, pe care o afișăm apoi pe ecran

șir strInput;

inf >> strInput;

cout<< strInput << endl ;

retur 0;

// Când inf iese din sfera de aplicare, destructorul clasei ifstream ne va închide automat fișierul

Vedea
linia
#1!
Vedea
linia
#2!

Hmm, nu exact asta am vrut. După cum știm deja din lecțiile anterioare, operatorul de extragere funcționează cu „date formatate”, adică. ignoră toate spațiile, filele și caracterele de linie nouă. Pentru a citi întregul conținut așa cum este, fără a-l descompune în părți (ca în exemplul de mai sus), trebuie să îl folosim metoda getline ():

#include #include #include #include // pentru a utiliza exit () int main () (folosind spațiul de nume std; // ifstream este utilizat pentru a citi conținutul fișierelor // Vom încerca să citim conținutul fișierului SomeText.txt ifstream inf („SomeText.txt "); // Dacă nu putem deschide fișierul pentru a-i citi conținutul dacă (! Inf) (// Apoi afișăm următorul mesaj de eroare și executăm exit () cerr<< "Uh oh, SomeText.txt could not be opened for reading!" << endl; exit(1); } // Пока есть, что читать while (inf) { // То перемещаем то, что можем прочитать, в строку, а затем выводим эту строку на экран string strInput; getline(inf, strInput); cout << strInput << endl; } return 0; // Когда inf выйдет из области видимости, то деструктор класса ifstream автоматически закроет наш файл }

#include

#include

#include

#include // a folosi exit ()

int main ()

folosind spațiul de nume std;

// ifstream este folosit pentru a citi conținutul fișierelor

ifstream inf ("SomeText.txt");

// Dacă nu putem deschide fișierul pentru a citi conținutul acestuia

dacă (! inf)

// Apoi afișăm următorul mesaj de eroare și executăm exit ()

cerr<< "Uh oh, SomeText.txt nu a putut fi deschis pentru citire!"<< endl ;

ieșire (1);

în timp ce (inf)

șir strInput;

getline (inf, strInput);

cout<< strInput << endl ;

retur 0;

// Când inf iese din sfera de aplicare, destructorul clasei ifstream ne va închide automat fișierul

Rezultatul executării programului de mai sus:

Ieșire tamponată

Ieșirea C ++ poate fi tamponată. Aceasta înseamnă că tot ceea ce este trimis în fluxul de fișiere nu poate fi scris imediat pe disc (într-un anumit fișier). Acest lucru se face în principal din motive de performanță. Când datele tampon sunt scrise pe disc, acestea sunt numite spălând tamponul... O modalitate de a goli tamponul este închiderea fișierului. În acest caz, întregul conținut al bufferului va fi mutat pe disc și apoi fișierul va fi închis.

Tamponul de ieșire nu este, de obicei, o problemă, dar în anumite circumstanțe poate provoca probleme pentru novicii neatenți. De exemplu, atunci când datele sunt stocate într-un buffer și programul își încheie execuția prematur (fie ca urmare a unei eșecuri, fie prin apelare). În astfel de cazuri, destructorii clasei I / O de fișiere nu sunt executați, fișierele nu sunt niciodată închise, tampoanele nu sunt spălate și datele noastre se pierd definitiv. Acesta este motivul pentru care este o idee bună să închideți explicit toate fișierele deschise înainte de a apela exit ().

De asemenea, tamponul poate fi șters manual folosind metoda ostream :: flush () sau prin trimitere std :: flush la fluxul de ieșire. Oricare dintre aceste metode poate fi utilă pentru a vă asigura că conținutul bufferului este scris pe disc imediat în caz de blocare a programului.

O nuanță interesantă: Din moment ce std :: endl; șterge de asemenea fluxul de ieșire, utilizarea excesivă a acestuia (ducând la spălări tampon inutile) poate afecta performanța programului (deoarece spălarea bufferului în unele cazuri poate fi o operațiune costisitoare). Din acest motiv, programatorii cărora le pasă de performanța codului lor folosesc adesea \ n în loc de std :: endl pentru a introduce o linie nouă în fluxul de ieșire pentru a evita spălarea tamponului inutilă.

Moduri deschidere fișier

Ce se întâmplă dacă încercăm să scriem date într-un fișier existent? Repornirea programului de mai sus (primul) arată că fișierul original este complet suprascris atunci când programul este repornit. Ce se întâmplă dacă trebuie să adăugăm date la sfârșitul fișierului? Se pare că fluxul de fișiere ia un al doilea parametru opțional, care vă permite să spuneți programatorului cum să deschidă fișierul. Ca acest parametru, puteți trece urmând steaguri(care fac parte din clasa ios):

aplicație- deschide fișierul în modul add;

a mancat- merge la sfârșitul fișierului înainte de citire / scriere;

binar- deschide fișierul în modul binar (în loc de modul text);

în- deschide fișierul în modul de citire (implicit pentru ifstream);

afară- deschide fișierul în modul de înregistrare (implicit pentru ofstream);

trunc- șterge fișierul dacă există deja.

Puteți specifica mai multe steaguri simultan folosind.

ifstream funcționează în mod implicit în ios :: în modul;

ofstream funcționează în mod ios :: out în mod implicit;

fstream implicit rulează în modul ios :: în modul OR ios :: out, ceea ce înseamnă că puteți face atât citirea conținutului unui fișier, cât și scrierea de date într-un fișier.

Acum, să scriem un program care adaugă două linii la fișierul SomeText.txt creat anterior:

#include #include // pentru a utiliza exit () #include int main () (folosind spațiul de nume std; // Treceți steagul ios: app pentru a spune fstream că vom adăuga datele noastre la datele existente ale fișierului, // nu vom suprascrie fișierul. Nu trebuie nu trebuie să treceți steagul ios :: out, // deoarece ofstream funcționează implicit în modul ios :: out out out mode ("SomeText.txt", ios :: app); // Dacă nu putem deschide fișierul pentru a scrie date if (! outf) (// Apoi vom afișa următorul mesaj de eroare și vom executa exit () cerr<< "Uh oh, SomeText.txt could not be opened for writing!" << endl; exit(1); } outf << "See line #3!" << endl; outf << "See line #4!" << endl; return 0; // Когда outf выйдет из области видимости, то деструктор класса ofstream автоматически закроет наш файл }

#include

#include // a folosi exit ()

#include

int main ()

folosind spațiul de nume std;

// Treceți steagul ios: app pentru a spune fstream că vom adăuga datele noastre la datele de fișiere existente,

// nu vom suprascrie fișierul. Nu este nevoie să trecem steagul ios :: out,

// deoarece ofstream funcționează în mod implicit ios :: out

ofstream outf ("SomeText.txt", ios :: app);

// Dacă nu putem deschide fișierul pentru a scrie date

dacă (! outf)

// Apoi afișăm următorul mesaj de eroare și executăm exit ()

cerr<< "Uh oh, SomeText.txt nu a putut fi deschis pentru scriere!"<< endl ;

ieșire (1);

Fișierele permit utilizatorului să citească cantități mari de date direct de pe disc fără să le introducă de la tastatură. Există două tipuri principale de fișiere: text și binar.

Text sunt numite fișiere constând din orice caractere. Acestea sunt organizate în linii, fiecare dintre care se termină cu „ sfârșitul liniei "... Sfârșitul fișierului în sine este indicat de simbolul „ sfârșitul fișierului "... Când scrieți informații într-un fișier text, care poate fi vizualizat folosind orice editor de text, toate datele sunt convertite într-un tip de caracter și stocate în formă de caractere.

ÎN binar fișiere, informațiile sunt citite și scrise sub formă de blocuri de o anumită dimensiune, în care pot fi stocate date de orice fel și structură.

Pentru a lucra cu fișiere, se utilizează tipuri de date speciale, numite pâraie. curgere ifstream servește pentru a lucra cu fișiere în modul de citire și ofstreamîn modul de înregistrare. Pentru a lucra cu fișiere atât în ​​modul de scriere, cât și în modul de citire, utilizați fluxul fstream.

În programele C ++, atunci când lucrați cu fișiere text, trebuie să includeți biblioteci iostreamși fstream.

Pentru a scrie date într-un fișier text, trebuie să:

  1. descrie o variabilă de tip ofstream.
  2. deschis.
  3. ieșire informații într-un fișier.
  4. asigurați-vă că închideți fișierul.

Pentru a citi date dintr-un fișier text, trebuie să:

  1. descrie o variabilă de tip ifstream.
  2. deschideți fișierul cu funcție deschis.
  3. citiți informații din fișier; la citirea fiecărei date, este necesar să verificați dacă a fost atins sfârșitul fișierului.
  4. închideți fișierul.

Scrierea informațiilor într-un fișier text

După cum sa menționat mai devreme, pentru a începe să lucrați cu un fișier text, trebuie să declarați o variabilă de acest tip ofstream... De exemplu, astfel:

ofstream F;

Se va crea o variabilă F pentru a scrie informații într-un fișier. Următorul pas este deschiderea fișierului pentru scriere. În general, operatorul de deschidere a fluxului va arăta astfel:

F.deschis("Fişier", modul);

Aici F este o variabilă descrisă ca ofstream, fişier- numele complet al fișierului pe disc, modul- modul de lucru cu fișierul deschis. Rețineți că trebuie să utilizați o bară dublă atunci când specificați numele complet al fișierului. Pentru a accesa, de exemplu, un fișier accounts.txt, aflat în dosar site-uri pe disc D, în program trebuie să specificați: D: \\ site-uri \\ conturi.txt.

Fișierul poate fi deschis în unul dintre următoarele moduri:

  • ios :: in- deschideți fișierul în modul de citire a datelor; modul este modul implicit pentru fluxuri ifstream;
  • ios :: afară- deschideți fișierul în modul de înregistrare a datelor (informațiile despre fișierul existent sunt distruse); modul este modul implicit pentru fluxuri ofstream;
  • ios :: app- deschideți fișierul în modul de scriere a datelor la sfârșitul fișierului;
  • ios :: ate- treceți la sfârșitul unui fișier deja deschis;
  • ios :: trunc- ștergeți fișierul, la fel se întâmplă și în modul ios :: out;
  • ios :: nocreate- nu efectuați operația de deschidere a unui fișier dacă acesta nu există;
  • ios :: noreplace- nu deschideți un fișier existent.

Parametrul de mod poate fi absent, în acest caz fișierul este deschis în modul implicit pentru acest flux.

După deschiderea cu succes a fișierului (în orice mod) în variabilă F va fi păstrat Adevărat, in caz contrar fals... Aceasta va verifica corectitudinea operației de deschidere a fișierului.

Deschideți un fișier (ca exemplu, luați fișierul D: \\ site-uri \\ conturi.txt) în modul de înregistrare într-unul din următoarele moduri:

După deschiderea fișierului în modul de scriere, va fi creat un fișier gol în care puteți scrie informații.

Dacă doriți să deschideți un fișier existent în modul suprascriere, utilizați valoarea ios :: app.

După deschiderea unui fișier în modul de scriere, puteți scrie pe acesta în același mod ca pe ecran, numai în locul dispozitivului de ieșire standard cout trebuie să specificați numele fișierului deschis.

De exemplu, pentru a scrie în flux F variabil A, operatorul de ieșire va fi:

F<

Pentru ieșire secvențială la un flux G variabile b, c, d declarația de ieșire devine:

G<

Fluxul este închis folosind operatorul:

F.închide ();

Luați în considerare următoarea problemă ca exemplu.

Problema 1

Creați fișier text D: \\ site-uri\\conturi .txtși scrie-i n numere reale.

Soluţie

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

#include "stdafx.h"
#include
#include
#include
folosind spațiul de nume std;
int main ()
{

int i, n;
dubla a;
// descrie un flux pentru scrierea datelor într-un fișier
ofstream f;
// deschideți fișierul în modul de scriere,
// Modul ios :: out este setat implicit
f.open („D: \\ site-uri \\ accounts.txt ", ios :: out);
// introduceți numărul numerelor reale
cout<< «n=» ; cin >> n;
// bucla pentru introducerea numerelor reale
// și scrieți-le într-un fișier
pentru (i = 0; i< n; i++ )
{
cout<< «a=» ;
// introduceți un număr
cin >> a;
f<< a<< «\ t ";
}
// închide fluxul
f.close ();
sistem („pauză”);
retur 0;
}

Citirea informațiilor dintr-un fișier text

Pentru a citi informații dintr-un fișier text, trebuie să declarați o variabilă de acest tip ifstream... După aceea, trebuie să deschideți fișierul pentru citire folosind operatorul deschis... Dacă se numește variabila F, atunci primii doi operatori vor fi astfel:

După deschiderea unui fișier în modul de citire, puteți citi informații din acesta în același mod ca și de la tastatură, doar în loc de cin trebuie să specificați numele fluxului din care vor fi citite datele.

De exemplu, pentru a citi date dintr-un flux Fîntr-o variabilă A, declarația de intrare va arăta astfel:

F >> a;

Două numere dintr-un editor de text sunt considerate separate dacă există cel puțin unul dintre caractere între ele: spațiu, tabelare, caracter de sfârșit de linie. Este bine când programatorul știe în avans câte și ce valori sunt stocate într-un fișier text. Cu toate acestea, adesea este cunoscut doar tipul de valori stocate în fișier, iar numărul lor poate varia. Pentru a rezolva această problemă, este necesar să citiți valorile din fișier una câte una și, înainte de fiecare citire, verificați dacă a fost atins sfârșitul fișierului. Iar funcția vă va ajuta să faceți acest lucru F.eof ()... Aici F- numele fluxului, funcția returnează o valoare booleană: Adevărat sau fals, în funcție de finalizarea fișierului.

Prin urmare, bucla pentru citirea conținutului întregului fișier poate fi scrisă astfel:

Pentru o mai bună asimilare a materialului, luați în considerare problema.

Sarcina 2

Fișierul text D: \\ game \\ accounts.txt stochează numerele reale, le afișează pe ecran și le calculează numărul.

Soluţie

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

#include "stdafx.h"
#include
#include
#include
#include
folosind spațiul de nume std;
int main ()
{
setlocale (LC_ALL, "RUS");
int n = 0;
plutitor a;
fstream F;
// deschideți fișierul în modul de citire
F.open („D: \\ site-uri \\ accounts.txt ") ;
// dacă fișierul a fost deschis corect, atunci
dacă (F)
{
// bucla pentru citirea valorilor dintr-un fișier; executarea ciclului va fi întreruptă,
// când ajungem la sfârșitul fișierului, în acest caz F.eof () va reveni adevărat.
while (! F.eof ())
{
// citiți următoarea valoare din fluxul F în variabila a
F >> a;
// afișează valoarea variabilei a pe ecran
cout<< a<< «\ t ";
// măriți numărul de numere citite
n ++;
}
// închide fluxul
F.închide ();
// introduceți pe ecran numărul de numere citite
cout<< «n=» << n<< endl;
}
// dacă fișierul a fost deschis incorect, atunci ieșirea
// mesaje despre absența unui astfel de fișier
altfel cout<< " Fisierul nu exista"<< endl;
sistem („pauză”);
retur 0;
}

Aceasta completează lecția relativ voluminoasă despre fișierele text. Următorul articol va analiza tehnicile de manipulare prin care se descurcă C ++.

Ultima actualizare: 31.10.2015

Există două clase pentru lucrul cu directoare în spațiul de nume System.IO: Directory și DirectoryInfo.

Clasa director

Clasa Directory oferă o serie de metode statice pentru gestionarea directoarelor. Unele dintre aceste metode sunt:

    CreateDirectory (cale): creează un director la calea specificată

    Ștergere (cale): șterge directorul de la calea specificată

    Exista (cale): Determina daca exista un director la calea specificata. Dacă există, revine adevărat, dacă nu există, atunci fals

    GetDirectories (cale): obține o listă de directoare din directorul căii

    GetFiles (cale): obține o listă de fișiere din directorul căii

    Mutare (sourceDirName, destDirName): mută directorul

    GetParent (cale): Obțineți directorul părinte

DirectoryInfo class

Această clasă oferă funcționalități pentru crearea, ștergerea, mutarea și alte operații cu directoare. În multe feluri, este similar cu Directory. Unele dintre proprietățile și metodele sale:

    Create (): creează un director

    CreateSubdirectory (cale): Creează un subdirector la calea specificată

    Delete (): șterge un director

    Exista proprietate: Determina daca directorul exista

    GetDirectories (): obține o listă de directoare

    GetFiles (): obține o listă de fișiere

    MoveTo (destDirName): mută un director

    Proprietate părinte: obțineți directorul părinte

    Proprietatea rădăcină: obțineți directorul rădăcină

Să vedem exemple de utilizare a acestor clase.

Obținerea unei liste de fișiere și subdirectoare

șir dirName = "C: \\"; if (Directory.Exists (dirName)) (Console.WriteLine ("Subdirectories:"); string dirs = Directory.GetDirectories (dirName); foreach (string s in dirs) (Console.WriteLine (s);) Console.WriteLine ( ); Console.WriteLine ("Fișiere:"); fișiere șir = Directory.GetFiles (dirName); foreach (șiruri în fișiere) (Console.WriteLine (s);))

Rețineți utilizarea barelor oblice în numele fișierelor. Fie folosim o bară dublă: „C: \\”, fie o bară unică, dar apoi punem semnul @ în fața întregii căi: @ „C: \ Program Files”

Crearea unui director

calea șirului = @ "C: \ SomeDir"; șir subpath = @ "program \ avalon"; DirectoryInfo dirInfo = nou DirectoryInfo (cale); if (! dirInfo.Exists) (dirInfo.Create ();) dirInfo.CreateSubdirectory (subpath);

Mai întâi, verificăm dacă există un astfel de director, deoarece dacă există, atunci nu va fi posibil să-l creăm, iar aplicația va arunca o eroare. Ca rezultat, obținem următoarea cale: "C: \ SomeDir \ program \ avalon"

Preluarea informațiilor din director

șir dirName = "C: \\ Fișiere de program"; DirectoryInfo dirInfo = nou DirectoryInfo (dirName); Console.WriteLine ($ "Nume director: (dirInfo.Name)"); Console.WriteLine ($ "Numele directorului complet: (dirInfo.FullName)"); Console.WriteLine ($ "Timp de creare a directorului: (dirInfo.CreationTime)"); Console.WriteLine ($ "Director rădăcină: (dirInfo.Root)");

Ștergerea unui director

Dacă aplicăm pur și simplu metoda Ștergere unui folder care nu conține fișiere sau subdirectoare, aplicația ne va arunca o eroare. Prin urmare, trebuie să trecem un parametru boolean suplimentar la metoda Delete, care va indica faptul că folderul ar trebui șters cu tot conținutul său:

String dirName = @ "C: \ SomeFolder"; try (DirectoryInfo dirInfo = new DirectoryInfo (dirName); dirInfo.Delete (true); Console.WriteLine ("Director șters");) catch (Exception ex) (Console.WriteLine (ex.Message);)

String dirName = @ "C: \ SomeFolder"; Directory.Delete (dirName, true);

Mutarea unui director

șir vechiPath = @ "C: \ SomeFolder"; șir newPath = @ "C: \ SomeDir"; DirectoryInfo dirInfo = nou DirectoryInfo (vechiPath); if (dirInfo.Exists && Directory.Exists (newPath) == false) (dirInfo.MoveTo (newPath);)

Atunci când vă deplasați, trebuie avut în vedere faptul că noul director, în care dorim să mutăm tot conținutul vechiului director, nu ar trebui să existe.

Pentru ușurință de referință, informațiile din dispozitivele de stocare sunt stocate sub formă de fișiere.

Fișierul este o zonă denumită de memorie externă alocată pentru stocarea unei matrice de date. Datele conținute în fișiere sunt de cea mai variată natură: programe în limbaj algoritmic sau de mașină; date inițiale pentru activitatea programelor sau rezultatele execuției programului; texte arbitrare; grafică etc.

Director (folder, director) - o colecție numită de octeți pe un mediu de stocare, care conține numele subdirectoarelor și fișierelor, este utilizată în sistemul de fișiere pentru a simplifica organizarea fișierelor.

Sistemul de fișiere este partea funcțională a sistemului de operare care oferă operațiuni pe fișiere. Exemple de sisteme de fișiere sunt FAT (FAT - File Allocation Table), NTFS, UDF (utilizate pe CD-uri).

Există trei versiuni principale ale FAT: FAT12, FAT16 și FAT32. Ele diferă în ceea ce privește bititatea înregistrărilor din structura discului, adică numărul de biți alocați pentru stocarea numărului de cluster. FAT12 este utilizat în principal pentru dischete (până la 4 KB), FAT16 pentru discurile mici, FAT32 pentru unitățile FLASH de mare capacitate (până la 32 GB).

Să ne uităm la structura sistemului de fișiere care utilizează FAT32 ca exemplu.

Structura fișierului FAT32

Dispozitivele de memorie externă din sistemul FAT32 nu au adresarea de octeți, ci blocarea adresării. Informațiile sunt scrise pe un dispozitiv de memorie extern în blocuri sau sectoare.

Un sector este cea mai mică unitate adresabilă de stocare a informațiilor pe dispozitive de stocare externe. De obicei, dimensiunea sectorului este fixată la 512 octeți. Pentru a crește spațiul de adresă al dispozitivelor de memorie externe, sectoarele sunt combinate în grupuri numite clustere.

Un cluster este o uniune de mai multe sectoare, care poate fi considerată ca o unitate independentă cu anumite proprietăți. Proprietatea principală a unui cluster este dimensiunea sa, măsurată în numărul de sectoare sau în numărul de octeți.

Sistemul de fișiere FAT32 are următoarea structură.

Clusterele utilizate pentru înregistrarea fișierelor sunt numerotate începând de la 2. De regulă, clusterul 2 este utilizat de directorul rădăcină și, începând de la clusterul 3, este stocată o matrice de date. Sectoarele utilizate pentru stocarea informațiilor prezentate deasupra directorului rădăcină nu sunt grupate.
Dimensiunea minimă a fișierului pe disc este de 1 cluster.

Sectorul de încărcare începe cu următoarele informații:

  • EB 58 90 - ramură necondiționată și semnătură;
  • 4D 53 44 4F 53 35 2E 30 MSDOS5.0;
  • 00 02 - numărul de octeți din sector (de obicei 512);
  • 1 octet - numărul de sectoare din cluster;
  • 2 octeți - numărul de sectoare de rezervă.

În plus, sectorul de încărcare conține următoarele informații importante:

  • 0x10 (1 octet) - numărul de tabele FAT (de obicei 2);
  • 0x20 (4 octeți) - numărul de sectoare de pe disc;
  • 0x2С (4 octeți) - numărul clusterului din directorul rădăcină;
  • 0x47 (11 octeți) - etichetă de volum;
  • 0x1FE (2 octeți) - semnătură sector boot (55 AA).

Sectorul informațional al sistemului de fișiere conține:

  • 0x00 (4 octeți) - semnătură (52 52 61 41);
  • 0x1E4 (4 octeți) - semnătură (72 72 41 61);
  • 0x1E8 (4 octeți) - numărul de clustere libere, -1 dacă nu se cunoaște;
  • 0x1EC (4 octeți) - numărul ultimului cluster înregistrat;
  • 0x1FE (2 octeți) - semnătură (55 AA).

FAT conține informații despre starea fiecărui cluster de pe disc. Cei 2 octeți inferiori ai magazinului FAT F8 FF FF 0F FF FF FF FF (care corespunde stării grupurilor 0 și 1, care sunt absente fizic). Mai mult, starea fiecărui cluster conține numărul clusterului în care continuă fișierul curent sau următoarele informații:

  • 00 00 00 00 - clusterul este gratuit;
  • FF FF FF 0F - sfârșitul fișierului curent.
  • 8 octeți - numele fișierului;
  • 3 octeți - extensie de fișier;

Directorul rădăcină conține un set de înregistrări de informații pe 32 de biți pentru fiecare fișier, conținând următoarele informații:

Când lucrați cu nume de fișiere lungi (inclusiv nume rusești), numele fișierului este codat în sistemul de codare UTF-16. În acest caz, sunt alocați 2 octeți pentru codificarea fiecărui caracter. În acest caz, numele fișierului este scris sub forma următoarei structuri:

  • 1 octet de secvență;
  • 10 octeți conțin cele mai puțin semnificative 5 caractere ale numelui fișierului;
  • Atribut 1 octet;
  • 1 octet rezervat;
  • 1 octet - suma de control a numelui DOS;
  • 12 octeți conțin cele mai puțin semnificative 3 caractere ale numelui fișierului;
  • 2 octeți - numărul primului cluster;
  • alte caractere ale numelui lung.

Lucrul cu fișiere în limbajul C.

Pentru programator, un fișier deschis este reprezentat ca o secvență de date citite sau scrise. Când fișierul este deschis, acesta este asociat cu Flux I / O... Informațiile de ieșire sunt scrise în flux, informațiile de intrare sunt citite din flux.

Când un flux este deschis pentru I / O, acesta se asociază cu o structură standard de tip FILE, care este definită în stdio.h. Structura FILE conține informațiile necesare despre fișier.

Fișierul este deschis folosind funcția fopen (), care returnează un pointer la o structură FILE, care poate fi utilizată pentru operațiuni ulterioare pe fișier.

FILE * fopen (nume, tip);


nume - numele fișierului de deschis (inclusiv calea),
type este un pointer către un șir de caractere care determină modul de accesare a fișierului:
  • "r" - deschideți un fișier pentru citire (fișierul trebuie să existe);
  • "w" - deschideți un fișier gol pentru scriere; dacă fișierul există, atunci conținutul său se pierde;
  • "a" - deschideți fișierul pentru scriere până la capăt (pentru adăugare); fișierul este creat dacă nu există;
  • "r +" - deschideți un fișier pentru citire și scriere (fișierul trebuie să existe);
  • "w +" - deschideți un fișier gol pentru citire și scriere; dacă fișierul există, atunci conținutul său se pierde;
  • „a +” - deschideți fișierul pentru citire și adăugare, dacă fișierul nu există, atunci este creat.

Valoarea returnată este un indicator către fluxul deschis. Dacă se întâlnește o eroare, NULL este returnat.

Funcția fclose () închide fluxul sau fluxurile asociate fișierelor deschise cu fopen (). Fluxul de închis este determinat de argumentul funcției fclose ().

Valoare returnată: valoarea 0, dacă fluxul a fost închis cu succes; EOF constant dacă a apărut o eroare.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

#include
int main () (
FIȘIER * fp;
char name = "my.txt";
if ((fp = fopen (nume, "r")) == NULL)
{
printf ( "Fișierul nu poate fi deschis");
getchar ();
retur 0;
}
// a reușit să deschidă fișierul
... // acțiuni necesare asupra datelor
fclose (fp);
getchar ();
retur 0;
}

Citirea unui personaj dintr-un fișier:

char fgetc (flux);


Argumentul funcției este un indicator către un flux de tip FILE. Funcția returnează codul caracterului citit. Dacă se ajunge la sfârșitul fișierului sau apare o eroare, EOF constantă este returnată.

Scrierea unui caracter într-un fișier:

fputc (caracter, flux);

Argumentele funcției sunt un caracter și un pointer către un flux de tip FILE. Funcția returnează codul caracterului citit.

Funcțiile fscanf () și fprintf () sunt similare cu funcțiile scanf () și printf (), dar funcționează cu fișiere de date și au un indicator de fișier ca prim argument.

fscanf (flux, "Format de intrare", argumente);



Ți-a plăcut articolul? Împărtășește-l