Për lehtësinë e aksesit, informacioni në pajisjet e ruajtjes ruhet në formën e skedarëve.
Skedari – zona e emërtuar memorie e jashtme, i dedikuar për ruajtjen e një grupi të dhënash. Të dhënat që përmbajnë skedarët janë të një natyre shumë të larmishme: programe në algoritmi ose gjuha e makinës; të dhënat fillestare për funksionimin e programit ose rezultatet e ekzekutimit të programit; tekste të lira; imazhe grafike e kështu me radhë.
Drejtori (dosje, drejtori) - një koleksion i emërtuar i bajteve në një medium ruajtjeje që përmban emrat e nëndirektorive dhe skedarëve, të përdorur në sistemin e skedarëve për të thjeshtuar organizimin e skedarëve.
Sistemi i skedarëve quhet pjesa funksionale sistemi operativ, duke ofruar operacione në skedarë. Shembuj të sistemeve të skedarëve janë FAT (FAT - Tabela e ndarjes së skedarëve), NTFS, UDF (përdoret në CD).
Ekzistojnë tre versione kryesore të FAT: FAT12, FAT16 dhe FAT32. Ato ndryshojnë në thellësinë e bitit të regjistrimeve në strukturën e diskut, d.m.th. numri i biteve të alokuara për të ruajtur numrin e grupit. FAT12 përdoret kryesisht për disqe (deri në 4 KB), FAT16 - për disqe të vegjël, FAT32 - për disqe FLASH kapacitet të madh(deri në 32 GB).
Le të shohim strukturën sistemi i skedarëve duke përdorur FAT32 si shembull.
Struktura e skedarit FAT32
Pajisjet e memories së jashtme në sistemin FAT32 kanë adresim blloku dhe jo adresim bajt. Informacioni shkruhet në një pajisje memorie të jashtme në blloqe ose sektorë.
Një sektor është njësia minimale e adresueshme e ruajtjes së informacionit në pajisjet e ruajtjes së jashtme. Në mënyrë tipike, madhësia e sektorit fiksohet në 512 bajt. Për të rritur hapësirën e adresave të pajisjeve të memories së jashtme, sektorët kombinohen në grupe të quajtura grupe.
Një grup është një bashkim i disa sektorëve, i cili mund të konsiderohet si një njësi e pavarur me veti të caktuara. Vetia kryesore e një grupi është madhësia e tij, e matur në numrin e sektorëve ose numrin e bajteve.
Sistemi i skedarëve FAT32 ka strukturën e mëposhtme.
Grupet e përdorura për shkrimin e skedarëve numërohen duke filluar nga 2. Si rregull, grupi nr. 2 përdoret nga direktoria rrënjësore, dhe duke filluar nga grupi nr. 3, grumbullimi i të dhënave ruhet. Sektorët e përdorur për të ruajtur informacionin mbi direktorinë rrënjë nuk janë të grupuar.
Madhësia minimale e skedarit të kërkuar në disk korrespondon me 1 grup.
Sektori i nisjes fillon me informacionin e mëposhtëm:
- EB 58 90 – kërcim dhe nënshkrim i pakushtëzuar;
- 4D 53 44 4F 53 35 2E 30 MSDOS5.0;
- 00 02 – numri i bajteve në sektor (zakonisht 512);
- 1 bajt – numri i sektorëve në grup;
- 2 bajt – numri i sektorëve rezervë.
Përveç kësaj, sektori i nisjes përmban informacionin e mëposhtëm të rëndësishëm:
- 0x10 (1 bajt) – numri i tabelave FAT (zakonisht 2);
- 0x20 (4 bytes) - numri i sektorëve në disk;
- 0x2С (4 bytes) – numri i grupit të direktoriumit rrënjë;
- 0x47 (11 bytes) – etiketa e vëllimit;
- 0x1FE (2 bytes) - nënshkrim sektori i çizmeve(55 AA).
Sektori i informacionit të sistemit të skedarëve përmban:
- 0x00 (4 bytes) – nënshkrim (52 52 61 41);
- 0x1E4 (4 bytes) – nënshkrim (72 72 41 61);
- 0x1E8 (4 bytes) – numri i grupimeve të lira, -1 nëse nuk dihet;
- 0x1EC (4 bytes) – numri i grupit të fundit të regjistruar;
- 0x1FE (2 bytes) – nënshkrimi (55 AA).
Tabela FAT përmban informacione për gjendjen e çdo grupi në disk. 2 bajtët e poshtëm të tabelës FAT ruajnë F8 FF FF 0F FF FF FF FF (që korrespondon me gjendjen e grupimeve 0 dhe 1, të cilat mungojnë fizikisht). Më pas, gjendja e çdo grupi përmban numrin e grupit në të cilin skedari aktual vazhdon ose informacionin e mëposhtëm:
- 00 00 00 00 – grupi është falas;
- FF FF FF 0F – fundi i skedarit aktual.
- 8 bajt – emri i skedarit;
- 3 bajt – zgjerimi i skedarit;
Drejtoria rrënjësore përmban një grup të dhënash informacioni 32-bit për çdo skedar, që përmban informacionin e mëposhtëm:
Në rast të punës me emra të gjatë skedarë (përfshirë emrat rusë), emri i skedarit është i koduar në sistemin e kodimit UTF-16. Në këtë rast, 2 bajt ndahen për kodimin e çdo karakteri. Në këtë rast, emri i skedarit shkruhet në strukturën e mëposhtme:
- 1 bajt sekuence;
- 10 bajt përmbajnë 5 karakteret e poshtme të emrit të skedarit;
- atribut 1 bajt;
- 1 bajt i rezervuar;
- 1 bajt - shuma e kontrollit emri i DOS;
- 12 bajt përmbajnë 3 karakteret e poshtme të emrit të skedarit;
- 2 bajt – numri i grupit të parë;
- personazhet e mbetura të emrit të gjatë.
Puna me skedarë në gjuhën C
Për programuesin skedari i hapur përfaqësohet si një sekuencë e të dhënave që lexohen ose shkruhen. Kur hapet një skedar, ai lidhet me Transmetimi I/O. Informacioni dalës shkruhet në rrjedhë, informacioni hyrës lexohet nga transmetimi.
Kur një transmetim hapet për I/O, ai shoqërohet me një strukturë standarde FILE, e cila përcaktohet në stdio.h. Struktura FILE përmban informacionin e nevojshëm në lidhje me dosjen.
Hapja e një skedari bëhet duke përdorur funksionin fopen(), i cili kthen një tregues në një strukturë FILE që mund të përdoret për operacionet e mëvonshme në skedar.
FILE *fopen(emri, lloji);
emri – emri i skedarit që do të hapet (përfshirë rrugën),
lloji është një tregues për një varg karakteresh që përcaktojnë se si aksesohet skedari:
- "r" - hapni skedarin për lexim (skedari duhet të ekzistojë);
- "w" - i hapur skedar bosh për regjistrim; nëse skedari ekziston, përmbajtja e tij humbet;
- "a" - hapni skedarin për shkrim deri në fund (për shtim); skedari krijohet nëse nuk ekziston;
- "r+" - hapni skedarin për lexim dhe shkrim (skedari duhet të ekzistojë);
- "w+" - hapni një skedar bosh për lexim dhe shkrim; nëse skedari ekziston, përmbajtja e tij humbet;
- "a+" - hapni skedarin për lexim dhe shtim; nëse skedari nuk ekziston, atëherë ai krijohet.
Vlera e kthyer është një tregues për rrjedhën e hapur. Nëse haset një gabim, kthehet NULL.
Funksioni fclose() mbyll transmetimin ose transmetimet e lidhura me skedarët e hapur duke përdorur funksionin fopen(). Rrjedha që do të mbyllet përcaktohet nga argumenti i funksionit fclose().
Vlera e kthimit: vlera 0 nëse transmetimi u mbyll me sukses; EOF konstante nëse ka ndodhur një gabim.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#përfshi
int main() (
FILE *fp;
emri char = "my.txt" ;
nëse ((fp = fopen (emri, "r" )) == NULL)
{
printf( "Dështoi në hapjen e skedarit");
getchar ();
kthimi 0;
}
// arriti të hapte skedarin
... // veprimet e nevojshme mbi të dhënat
fclose(fp);
getchar ();
kthimi 0;
}
Leximi i një karakteri nga një skedar:
char fgetc(rrymë);
Argumenti i funksionit është një tregues drejt një rryme të tipit FILE. Funksioni kthen kodin e karakterit të lexuar. Nëse arrihet fundi i skedarit ose ndodh një gabim, EOF konstante kthehet.
Shkrimi i një simboli në një skedar:
fputc (char, stream);
Argumentet e funksionit janë një karakter dhe një tregues drejt një rryme të tipit FILE. Funksioni kthen kodin e karakterit të lexuar.
Funksionet fscanf() dhe fprintf() janë të ngjashëm funksionet e skanimit() dhe printf() , por punojnë me skedarë të dhënash dhe kanë një tregues për skedarin si argumentin e tyre të parë.
fscanf(stream, "InputFormat", argumente);
Regjistroni informacionin në skedar teksti ne kemi mësuar tashmë. – Nëse nuk e keni mësuar se si, shihni artikullin e mëparshëm. Tregohet dhe përshkruhet në detaje
Por, çka nëse skedari tashmë ekziston dhe ne duhet të lexojmë informacion prej tij për përpunim? Për fat të mirë, kjo është gjithashtu mjaft e thjeshtë. Më lejoni t'ju kujtoj se ka disa opsione për zbatimin e kësaj detyre; unë kam përshkruar vetëm një prej tyre. Ai i përshkruar është ai që për disa arsye mua personalisht më duket më i lehtë për t'u kuptuar.
#përfshi
int main()
{
char s1 //Ndryshorja do të lexojë vargun
ifstream in (“C:\\\FromC\\myfile.txt”); //Hapni skedarin për të lexuar informacionin
në >>s1 ; //lexoni rreshtin
in.close() // Mbyllja e skedarit
cout<
kthimi 0;
}
Këtu është programi më i thjeshtë për të lexuar rreshtin e parë nga një skedar teksti i vendosur përgjatë shtegut
C:\\\FromC\\myfile.txt –
Meqenëse ky është një vazhdim i artikullit të mëparshëm, vendosa të përdor skedarin që krijuam atje. Ndoshta nuk duhet të ketë ndonjë vështirësi me këtë.
Por le të kthehemi te kodi. Fillimisht hapim skedarin për të lexuar informacion prej tij, për këtë përdorim komandën ifstream në kllapa tregojmë ose emrin e skedarit ose rrugën drejt skedarit, siç bëra unë. (“C:\\\FromC\\myfile.txt”);
Kur hapëm një skedar për të lexuar diçka prej tij, ne deklaruam një variabël si karakter -
karakteri s1
Tani gjithçka që duhet të bëjmë është t'i caktojmë variablit vlerën e vargut nga skedari. Ne e bëjmë këtë si një ekip në
Kushtojini vëmendje kllapave këndore në >>
Në fakt, siç duhet të jetë e qartë nga komentet në kodin e programit, në mënyrë që ndryshorja të caktojë vlerën e leximit, ne duhet ta shkruajmë atë pas në >>
në >>s1 ;
Asgje speciale detyrë sfiduese kjo nuk duket e mundur, veçanërisht nëse tashmë e keni zotëruar dhe mësuar të përdorni materialin nga artikulli i mëparshëm - gjithçka është absolutisht e njëjtë, vetëm 2 komanda janë të ndryshme
Krijimi i një skedari dhe shkrimi i informacionit C++ në të
të rrjedhës jashtë
( Emri i skedarit );
jashtë<< (Varg për t'u shkruar);
jashtë.mbyll();
=============================
Leximi i tekstit nga një skedar dhe printimi i tekstit në ekran në C++
ifstream në
(Emri i skedarit);
në>>
(Duke lexuar rreshtin);
në.mbyll();(Mbyll skedarin)
============================
Le të shkruajmë një program i thjeshtë, i cili do të lexojë futjen e tekstit të tastierës dhe do ta shkruajë atë në një skedar:
#përfshi
#përfshi
int main()
{
\\
3 linja të ardhshme
clrscsr(); // Pastrimi i ekranit
cout<<“Wwedi pervuu stroku”
;
cin >>a ; endl ;
cout<<“Wwedi wtoruu stroku”
;
cin >>b ; endl ;
cout<<“Wwedi tretuu stroku”
;
cin >>c ; endl ;
clrscr(); //
/*Filloni të punoni me skedarin*/
outstream out (“C:\\\FromC\\myfile.txt”); //Hapja e një skedari për të shkruar
jashtë<Shkruani rreshtin e parë
jashtë<Shkruani rreshtin e dytë
jashtë<
out.close(); // Mbyllja e skedarit
//Rivendosja e variablave
për (int i =0 ;i<=255
;i
++)
(a =*“” ; b =*“” ; c =*“” ;)
ifstream ne ("C:\\\FromC\\myfile.txt");
në >>a >>b >>c ; //Ne lexojmë çdo rresht të ri në një ndryshore të re
in.close(); // Mbyllja e skedarit
/* */
për (i =0 ;a !=*“” ;i ++)
{
nëse (i > madhësia e (a )) pushim ;
cout<
}
cout<<“\n”
; \\
/* */
{
nëse (i > madhësia e (b)) pushim ;
cout<
}
cout<<“\n”
; \\
Zhvendos kursorin në një rresht të ri
/* */
për (i =0 ;с !=*“” ;i ++)
{
nëse (i > madhësia e (c )) pushim ;
cout<<с
;
}
kthimi 0;
}
===================
Në shembujt e mësipërm ka një të tillë E MADHE e metë. Nëse përpiqemi të fusim një rresht që përmban hapësira, programi nuk do të funksionojë siç duhet. Ndoshta, jo vetëm unë, por edhe shumë njerëz të tjerë hasëm në këtë gabim. Prandaj, unë lë kodin e pasaktë në mënyrë që të shihni se çfarë mund të hasni.
Meqenëse nuk ka libra në shtëpi, unë përsëri fillova të kontrolloj internetin dhe gjeta shumë lloj-lloj marrëzish të sofistikuara. Por disi gjeta një zgjidhje për problemin tim.
Më ndihmoi që e lexova cout mbështet metodat e tij. Dhe në internet të gjitha këshillat shkojnë drejt përdorimit të funksionit linjë të marrë Për fatin tim, zbulova se si ta përdor këtë funksion shumë shpejt dhe më pas e përdora në kod.
Në përgjithësi, ia vlen të përmendet dhe të përshkruhet ky funksion, por deri më tani nuk e kuptoj vërtet, thjesht e kuptoj që duhet të përdoret dhe e kuptoj se si, kështu që do të jap një shembull më të saktë të programit tonë që po zhvillohet. :
#përfshi
#përfshi
int main()
{
karakter a,b,c; \\
3 linja të ardhshme
clrscsr(); // Pastrimi i ekranit
/* Futni vlerat për variablat*/
cout<<“Wwedi pervuu stroku”
;
cin.getline(a,madhësia e(a)); endl ;
cout<<“Wwedi wtoruu stroku”
;
cin.getline(a,madhësia e(b)); endl ;
cout<<“Wwedi tretuu stroku”
;
cin.getline(a,madhësia e(c)); endl ;
clrscr(); //Pas futjes së vlerave, ekrani u fshi
/*Filloni të punoni me skedarin*/
outstream out ("C:\\\FromC\\myfile.txt"); // Hapja e një skedari për të shkruar
jashtë<Shkruani rreshtin e parë
jashtë<Shkruani rreshtin e dytë
jashtë<
out.close(); // Mbyllja e skedarit
//Rivendosja e variablave
për (int i =0 ;i<=255
;i
++)
(a =*“” ; b =*“” ; c=*“” ;)
/*Vazhdo të punosh me skedarin*/
nëse transmetoni në ("C:\\\FromC\\myfile.txt");
in.getline(a,madhësia e(a));//
A
in.getline(b,madhësia e(b));//
Leximi i një rreshti në një ndryshore b
in.getline(c,madhësia e(c));
//
Leximi i një rreshti në një ndryshore c
in.close(); // Mbyllja e skedarit
/* Ne lexojmë rreshtin e parë karakter për karakter dhe e shfaqim atë në ekran */
për (i =0 ;a !=*“” ;i++)
{
nëse (i > madhësia e (a )) pushim ;
cout<
}
cout<<“\n”
; \\
Zhvendos kursorin në një rresht të ri
/* Ne lexojmë rreshtin e dytë karakter për karakter dhe e shfaqim atë në ekran */
për (i =0 ;b !=*“” ;i ++)
{
nëse (i > madhësia e (b)) pushim ;
cout<
}
cout<<“\n”
; \\
Zhvendos kursorin në një rresht të ri
/* Ne lexojmë rreshtin e tretë karakter për karakter dhe e shfaqim atë në ekran */
për (i =0 ;с !=*“” ;i++)
{
nëse (i> madhësia e (c)) pushim ;
cout<<с[i];
}
getch(); \\Pritet që tasti Enter të shtypet
kthimi 0;
}
===================
Ky material përshkruan një shembull të leximit karakter pas karakteri të informacionit. Meqenëse nuk e përshkrova punën me variabla si karakter, atëherë fillestarët mund të përjetojnë disa shqetësime në kuptimin e kodit. Thjesht nuk e dija se çfarë lloji karakter ka disa veçori dhe mendoi se gjithçka ishte më e thjeshtë. Prandaj, disa momente të pakuptueshme të programit të mësipërm mund të lexohen në artikullin e mëposhtëm duke punuar me char V C++ për fillestarët
Përndryshe, shembulli i dhënë se si të lexohen rreshtat nga një skedar teksti në C++ duhet të jetë i arritshëm dhe mjaft i kuptueshëm. Ky nuk është opsioni optimal i zbatimit për momentin dhe më kanë humbur disa pika të rëndësishme, por duke qenë se po fillojmë të mësojmë gjuhën C++, kjo është mjaft e mjaftueshme për momentin. Më vonë ndoshta do të arrij tek ajo që më ka munguar, por tani më duhet të perceptoj vetëm më të nevojshmen.
Nëse ju dhe unë e kuptojmë këtë material, do të thotë se kemi bërë një hap të vogël drejt profesionalizmit tonë.
Shënim:
pushim ;– Kjo është komanda që del nga cikli. Kemi nëse numëruesi i ciklit për bëhet më e madhe se madhësia e deklaruar e ndryshores karamel, atëherë me forcë dalim nga laku
!= –
Ky është kushti që kemi vendosur. Ky kusht shënohet me pabarazi
nëse (a !=b)– Lexon sikur a jo të barabartë b
endl ; - Kjo po lëviz kursorin në një linjë të re brenda tastierës (me sa kuptoj unë)
Kjo komandë është e ngjashme me "\n"
Shumica e programeve kompjuterike punojnë me skedarë, dhe për këtë arsye ekziston nevoja për të krijuar, fshirë, shkruar, lexuar, hapur skedarë. Çfarë është një skedar? Një skedar është një grup i emërtuar bajtësh që mund të ruhen në disa pajisje ruajtëse. Epo, tani është e qartë se një skedar nënkupton një sekuencë të caktuar bajtësh që ka emrin e vet unik, për shembull file.txt. Skedarët me të njëjtët emra nuk mund të vendosen në të njëjtin drejtori. Emri i skedarit i referohet jo vetëm emrit të tij, por edhe shtrirjes së tij, për shembull: file.txt dhe file.dat — skedarë të ndryshëm, megjithëse kanë të njëjtin emër. Ekziston një gjë e tillë si emri i plotë i skedarit - kjo është adresa e plotë në drejtorinë e skedarit që tregon emrin e skedarit, për shembull: D:\docs\file.txt. Është e rëndësishme të kuptohen këto koncepte bazë, përndryshe do të jetë e vështirë të punosh me skedarë.
Për të punuar me skedarë, duhet të përfshini një skedar me kokë
Skedari I/O është i ngjashëm me I/O standarde, i vetmi ndryshim është se I/O kryhet në një skedar dhe jo në ekran. Nëse I/O në pajisjet standarde kryhet duke përdorur objektet cin dhe cout, atëherë për të organizuar skedarin I/O mjafton të krijoni objektet tuaja që mund të përdoren në mënyrë të ngjashme me operatorët cin dhe cout.
Për shembull, duhet të krijoni një skedar teksti dhe të shkruani në të rreshtin Working with files në C++. Për ta bërë këtë ju duhet të ndërmerrni hapat e mëposhtëm:
- krijoni një objekt të klasës ofstream ;
- shoqëroni një objekt të klasës me skedarin që duhet shkruar;
- shkruani një rresht në një skedar;
- mbyll skedarin.
Pse është e nevojshme të krijohet një objekt ofstream në vend të një objekti ifstream? Sepse ju duhet të shkruani në një skedar, dhe nëse keni nevojë të lexoni të dhëna nga një skedar, do të krijohej një objekt i klasës ifstream.
// krijoni një objekt për shkrim në skedarin e rrjedhës /*emri i objektit*/; // objekt i klasës ofstream
Le ta quajmë objektin "fout". Kjo është ajo që marrim:
Fout jashtë rrjedhës;
Pse na duhet një objekt? Objekti duhet të jetë në gjendje të shkruajë në një skedar. Objekti tashmë është krijuar, por nuk është i lidhur me skedarin në të cilin duhet të shkruhet vargu.
Fout.open ("cppstudio.txt"); // shoqëroni objektin me skedarin
Nëpërmjet operacionit dot, ne fitojmë qasje në metodën e klasës open(), në të cilën tregojmë emrin e skedarit në kllapa. Skedari i specifikuar do të krijohet në drejtorinë aktuale me programin. Nëse ekziston një skedar me të njëjtin emër, skedari ekzistues do të zëvendësohet me një të ri. Pra, skedari është i hapur, gjithçka që mbetet është të shkruani rreshtin e kërkuar në të. Kjo bëhet si kjo:
Fout<< "Работа с файлами в С++"; // запись строки в файл
Duke përdorur funksionin stream në lidhje me objektin fout, vargu Puna me skedarë në C++ shkruhet në një skedar. Meqenëse nuk ka më nevojë për ndryshimin e përmbajtjes së skedarit, ai duhet të mbyllet, domethënë, objekti duhet të ndahet nga skedari.
Fout.close(); // mbyll skedarin
Rezultati - u krijua një skedar me rreshtin Puna me skedarë në C++.
Hapat 1 dhe 2 mund të kombinohen, domethënë, në një rresht, të krijoni një objekt dhe ta lidhni atë me një skedar. Kjo bëhet si kjo:
Ofstream fout("cppstudio.txt"); // krijoni një objekt të klasës ofstream dhe shoqëroni atë me skedarin cppstudio.txt
Le të kombinojmë të gjithë kodin dhe të marrim programin e mëposhtëm.
// file.cpp: Përcakton pikën hyrëse për aplikacionin e konsolës. #include "stdafx.h" #include
Mbetet të kontrolloni nëse programi po funksionon siç duhet dhe për ta bërë këtë, hapni skedarin cppstudio.txt dhe shikoni përmbajtjen e tij, duhet të jetë - Puna me skedarë në C++.
- krijoni një objekt të klasës ifstream dhe lidhni atë me skedarin nga i cili do të kryhet leximi;
- lexoni skedarin;
- mbyll skedarin.
Programi tregon dy mënyra për të lexuar nga një skedar, e para është përdorimi i operacionit të transferimit në një transmetim, e dyta është përdorimi i funksionit getline () . Në rastin e parë lexohet vetëm fjala e parë dhe në rastin e dytë lexohet një varg me gjatësi 50 karaktere. Por duke qenë se në skedar kanë mbetur më pak se 50 karaktere, lexohen karakteret deri dhe duke përfshirë të fundit. Ju lutemi vini re se duke lexuar herën e dytë (rreshti 17) vazhdoi pas fjalës së parë, dhe jo nga fillimi, pasi fjala e parë u lexua nërreshti 14. Rezultati i programit është paraqitur në Figurën 1.
Puna me skedarë në C++ Për të vazhduar, shtypni çdo tast. . .
Figura 1 - Puna me skedarë në C++
Programi funksionoi si duhet, por kjo nuk ndodh gjithmonë, edhe nëse gjithçka është në rregull me kodin. Për shembull, emri i një skedari joekzistent iu kalua programit ose kishte një gabim në emër. Po pastaj? Në këtë rast, asgjë nuk do të ndodhë fare. Skedari nuk do të gjendet, që do të thotë se nuk do të jetë e mundur të lexohet. Prandaj, përpiluesi do të injorojë linjat ku kryhet puna në skedar. Si rezultat, programi do të dalë siç duhet, por asgjë nuk do të shfaqet në ekran. Duket se ky është një reagim krejtësisht normal ndaj një situate të tillë. Por një përdorues i thjeshtë nuk do të kuptojë se çfarë po ndodh dhe pse rreshti nga skedari nuk u shfaq në ekran. Pra, për të bërë gjithçka shumë të qartë, C++ ofron një funksion të tillë - is_open(), i cili kthen vlera të plota: 1 - nëse skedari është hapur me sukses, 0 - nëse skedari nuk është hapur. Le të modifikojmë programin me hapjen e një skedari, në mënyrë që nëse skedari nuk është i hapur, të shfaqet një mesazh përkatës.
// file_read.cpp: Përcakton pikën hyrëse për aplikacionin e konsolës. #include "stdafx.h" #include
Rezultati i programit është paraqitur në Figurën 2.
Skedari nuk mund të hapet! Për të vazhduar, shtypni çdo buton. . .
Figura 2 - Puna me skedarë në C++
Siç mund të shihet nga Figura 2, programi raportoi se ishte e pamundur të hapej skedari. Prandaj, nëse programi punon me skedarë, rekomandohet të përdorni këtë funksion, is_open(), edhe nëse jeni të sigurt që skedari ekziston.
Mënyrat e hapjes së skedarëve
Mënyrat e hapjes së skedarëve përcaktojnë se si përdoren skedarët. Për të vendosur modalitetin, klasa ios_base ofron konstante që përcaktojnë mënyrën e hapjes së skedarit (shih Tabelën 1).
Mënyrat e hapjes së skedarit mund të vendosen drejtpërdrejt kur krijoni një objekt ose kur thirrni funksionin open(). .
Ofstream fout("cppstudio.txt", ios_base::app); // hapni skedarin për të shtuar informacion në fund të skedarit fout.open("cppstudio.txt", ios_base::app); // hapni skedarin për të shtuar informacion në fund të skedarit
Mënyrat e hapjes së skedarëve mund të kombinohen duke përdorur një operacion logjik në bit ose| , për shembull: ios_base::out | ios_base::trunc - hap një skedar për shkrim pas pastrimit të tij.
Objektet e klasës ofstream, kur shoqërohen me skedarë, përmbajnë si parazgjedhje mënyrat e hapjes së skedarëve ios_base::out | ios_base:: trunc . Kjo do të thotë, skedari do të krijohet nëse nuk ekziston. Nëse skedari ekziston, përmbajtja e tij do të fshihet dhe vetë skedari do të jetë gati për shkrim. Objektet e klasës ifstream, kur shoqërohen me një skedar, kanë mënyrën e paracaktuar të hapjes së skedarit ios_base::in - skedari është i hapur vetëm për lexim. Mënyra e hapjes së skedarit quhet gjithashtu një flamur; për lexueshmëri, ne do ta përdorim këtë term në të ardhmen. Tabela 1 nuk rendit të gjithë flamujt, por këto duhet të jenë të mjaftueshme për të filluar.
Vini re se flamujt ate dhe app janë shumë të ngjashëm në përshkrim, ata të dy e lëvizin treguesin në fund të skedarit, por flamuri i aplikacionit lejon vetëm shkrimin në fund të skedarit dhe flamuri i ate thjesht e zhvendos flamurin deri në fund të skedarit dhe nuk kufizon vendin ku të shkruhet.
Le të zhvillojmë një program që, duke përdorur operacionin sizeof(), do të llogarisë karakteristikat e llojeve kryesore të të dhënave në C++ dhe do t'i shkruajë ato në një skedar. Karakteristikat:
- numri i bajteve të alokuara për llojin e të dhënave
- vlera maksimale që mund të ruajë një lloj i caktuar i të dhënave.
Skedari duhet të shkruhet në formatin e mëposhtëm:
/* tipi i të dhënave vlera maksimale e bajtit bool = 1 255.00 char = 1 255.00 int i shkurtër = 2 32767.00 int i shkurtër i panënshkruar = 2 65535.00 int = 4 2147483647.00 i panënshkruar 29 int = 4904 i gjatë = 4904 47. 00 e panënshkruar gjatë int = 4 4294967295.00 float = 4 2147483647.00 notim i gjatë = 8 9223372036854775800.00 dyfish = 8 9223372036854775800.00 */
Një program i tillë ishte zhvilluar tashmë më herët në seksion, por atje të gjitha informacionet në lidhje me llojet e të dhënave u nxorrën në pajisjen standarde të daljes dhe ne duhet ta ribëjmë programin në mënyrë që informacioni të shkruhet në një skedar. Për ta bërë këtë, duhet të hapni skedarin në modalitetin e shkrimit, me shkurtimin paraprak të informacionit aktual të skedarit ( rreshti 14). Pasi të krijohet skedari dhe të hapet me sukses (rreshtat 16 - 20), në vend të deklaratës cout, në rreshti 22 ne përdorim objektin fout. kështu, në vend të ekranit, informacioni i llojit të të dhënave do të shkruhet në një skedar.
// write_file.cpp: Përcakton pikën hyrëse për aplikacionin e konsolës. #include "stdafx.h" #include
Është e pamundur të mos vërehet se ndryshimet në program janë minimale, dhe gjithçka falë faktit se hyrje/dalja standarde dhe hyrja/dalja e skedarit përdoren saktësisht në të njëjtën mënyrë. Në fund të programit, nërreshti 45Ne e mbyllëm skedarin në mënyrë eksplicite, megjithëse kjo nuk është e nevojshme, por konsiderohet praktikë e mirë programimi. Vlen të përmendet se të gjitha funksionet dhe manipuluesit e përdorur për të formatuar hyrjen/daljet standarde janë gjithashtu të rëndësishme për hyrjen/daljen e skedarit. Prandaj, nuk ka pasur gabime gjatë deklaratës cout u zëvendësua nga një objekt grindje.
Puna me skedarë teksti në C++.
Ekzistojnë dy lloje kryesore të skedarëve: tekst dhe binar. Skedarët lejojnë përdoruesin të lexojë sasi të mëdha të dhënash drejtpërdrejt nga disku pa pasur nevojë t'i futë ato nga tastiera.
Teksti thirren skedarët që përbëhen nga ndonjë karakter. Ato janë të organizuara në rreshta, secila përfundon me një karakter fundor. Fundi i vetë skedarit tregohet me simbolin "fundi i skedarit". Kur shkruani informacion në një skedar teksti, i cili mund të shikohet duke përdorur çdo redaktues teksti, të gjitha të dhënat konvertohen në një lloj karakteri dhe ruhen në formën e karaktereve.
NË binare Në skedarë, informacioni lexohet dhe shkruhet në formën e blloqeve të një madhësie të caktuar, në të cilat mund të ruhen të dhëna të çdo lloji dhe strukture.
Për të punuar me skedarë, të veçantë llojet e të dhënave, thirri përrenj. Rrjedha ifstream përdoret për të punuar me skedarë në modalitetin e leximit dhe të rrjedhës në modalitetin e regjistrimit. Për të punuar me skedarë në modalitetin e shkrimit dhe të leximit, përdoret një transmetim fstream.
Në programet C++, kur punoni me skedarë teksti, duhet të përfshini bibliotekat iostream dhe fstream.
Në mënyrë që shkruani të dhënat në një skedar teksti, ju nevojiten:
përshkruani një variabël të llojit të rrjedhës.
nxirrni informacionin në një skedar.
sigurohuni që ta mbyllni skedarin.
Për duke lexuar të dhëna nga një skedar teksti, ju nevojiten:
përshkruani një variabël të tipit ifstream.
hapni një skedar duke përdorur funksionin e hapur.
mbyll skedarin.
Regjistro informacion në një skedar teksti
Siç u përmend më herët, për të filluar punën me një skedar teksti, duhet të përcaktoni një variabël të llojit të rrjedhës. Për shembull, si kjo:
Një variabël F do të krijohet për të shkruar informacion në skedar.
Në fazën tjetër, skedari duhet të hapet për shkrim. Në përgjithësi, operatori i hapjes së rrjedhës do të duket kështu:
F.open ("skedar", modaliteti);
Këtu F është një ndryshore e përshkruar si rrjedhë,
skedar - emri i plotë i skedarit në disk,
modaliteti - mënyra e punës me skedarin që hapet.
Ju lutemi vini re se kur specifikoni emrin e plotë të skedarit, duhet të përdorni një prerje të dyfishtë. Për shembull, emri i plotë i skedarit noobs.txt, i vendosur në dosjen e lojës në diskun D:, do të duhet të shkruhet kështu:
D: \\ lojë \\ noobs.txt.
Skedari mund të hapet në një nga mënyrat e mëposhtme:
ios::in - hapni skedarin në modalitetin e leximit të të dhënave, kjo mënyrë është mënyra e paracaktuar për ifstreams;
ios::out - hapni një skedar në modalitetin e shkrimit të të dhënave (në këtë rast, informacioni për skedarin ekzistues shkatërrohet), ky modalitet është mënyra e paracaktuar për ofstreams;
ios::app - hapni skedarin në mënyrën e shkrimit të të dhënave deri në fund të skedarit;
ios::ate - lëvizni në fund të një skedari tashmë të hapur;
ios::trunc - pastroni skedarin, kjo ndodh edhe në modalitetin ios::out;
ios::nocreate - mos hapni një skedar nëse nuk ekziston;
ios::noreplace - mos hapni një skedar ekzistues.
Parametri i modalitetit mund të mungojë, në këtë rast skedari hapet në modalitetin e paracaktuar për këtë transmetim.
Pas hapjes me sukses të skedarit (në çdo modalitet), ndryshorja F do të ruajë true, përndryshe false. Kjo do t'ju lejojë të kontrolloni korrektësinë e operacionit të hapjes së skedarit.
Mund të hapni një skedar (le të marrim skedarin D:\\game\\noobs.txt si shembull) në modalitetin e regjistrimit në një nga mënyrat e mëposhtme:
// së pari mënyrë
i rrjedhës F;
F.open("D:\\loja\\noobs.txt", ios::out);
//metoda e dytë, modaliteti ios::out është modaliteti i paracaktuar
// Për rrjedhintë rrjedhës
i rrjedhës F;
//metoda e tretë kombinon përshkrimin e ndryshores dhe llojin e rrjedhës
//dhe hapja e skedarit në një deklaratë
ofstream F("D:\\game\\noobs.txt", ios::out);
Pas hapjes së skedarit në modalitetin e shkrimit, do të krijohet një skedar bosh në të cilin mund të shkruani informacion.
Nëse dëshironi të hapni një skedar ekzistues në modalitetin e shkrimit të parë, duhet të përdorni ios::app si modalitet.
Pas hapjes së një skedari në modalitetin e regjistrimit, mund t'i shkruani në të njëjtën mënyrë si në ekran, vetëm në vend të pajisjes standarde të daljescoutduhet të specifikoni emrin e skedarit të hapur.
Për shembull, për të shkruar variablin a në transmetimin F, deklarata e daljes do të duket si kjo:
Për daljen sekuenciale në rrjedhën G të variablave b, c, d, operatori i daljes do të bëhet si ky:
G<
Mbyllja e një transmetimi bëhet duke përdorur operatorin:
SHEMBULL:
Krijoni një skedar teksti D:\\game\\noobs.txt dhe shkruani n numra realë në të.
#include "stdafx.h"
#përfshi
#përfshi
#përfshi
duke përdorur namespace std;
int main()
setlocale (LC_ALL, "RUS");
int i, n;
dyfishi a;
//përshkruan një rrymë për shkrimin e të dhënave në një skedar
të rrjedhës f;
//hap skedarin në modalitetin e shkrimit,
//modalitetiios:: jashtëinstaluar si parazgjedhje
f.open("D:\\loja\\noobs.txt", ios::out);
//shkruani numrin e numrave realë
cout<<" n="; cin>> n;
//loop për futjen e numrave realë
//dhe shkruajini ato në një skedar
për (i=0; i
cout<<"a=";
//fut një numër
cin>>a;
//mbyllja e rrymës
f.close();
system ("pauzë");
kthimi 0;
_______________________________________________________________
Për të lexuar informacion nga një skedar teksti, duhet të përshkruani një variabël si p.sh ifstream. Pas kësaj, duhet të hapni skedarin për lexim duke përdorur operatorin hapur. Nëse ndryshorja quhet F, atëherë dy deklaratat e para do të jenë si kjo:
F.open("D:\\loja\\noobs.txt", ios::in);
Pas hapjes së një skedari në modalitetin e leximit, mund të lexoni informacion prej tij në të njëjtën mënyrë si nga tastiera, vetëm në vend tëcinspecifikoni emrin e rrymës nga e cila do të lexohen të dhënat.
Për shembull, për të lexuar nga rrjedha F në ndryshoren a, deklarata hyrëse do të duket si kjo:
Dy numra në një redaktues teksti konsiderohen të ndarë nëse ka të paktën një nga karakteret midis tyre: hapësirë, skedë, fund rreshti. Është mirë nëse programuesi e di paraprakisht sa dhe çfarë vlerash duhet të ruajë në skedarin e tekstit. Sidoqoftë, shpesh lloji i vlerave të ruajtura në skedar dihet thjesht, por numri i tyre mund të ndryshojë. Për të zgjidhur këtë problem, duhet të lexoni vlerat nga skedari një nga një dhe përpara çdo leximi, kontrolloni nëse është arritur fundi i skedarit. Ekziston një funksion për këtë F. eof().
Këtu F është emri i thread-it, funksioni kthen një vlerë Boolean: true ose false, në varësi të faktit nëse është arritur fundi i skedarit. Prandaj, një lak për të lexuar përmbajtjen e të gjithë skedarit mund të shkruhet si kjo:
//organizo për leximin e vlerave nga një skedar, ekzekutim
//ciku do të prishet kur të arrijmë në fund të skedarit,
//në këtë rast F.eof() do të kthehet true
ndërsa (!F.eof())
SHEMBULL:
Skedari i tekstit D:\\game\\noobs.txt ruan numrat realë, i shfaq në ekran dhe llogarit numrin e tyre.
#include "stdafx.h"
#përfshi
#përfshi
#përfshi
#përfshi
duke përdorur namespace std;
int main()
setlocale (LC_ALL, "RUS");
int n=0;
noton a;
fstream F;
//hap skedarin në modalitetin e leximit
F.open("D:\\loja\\noobs.txt");
//nëse skedari është hapur saktë, atëherë
//loop për leximin e vlerave nga një skedar; ekzekutimi i lakut do të ndërpritet,
//kur të arrijmë në fund të skedarit, në këtë rast F.eof() do të kthehet true.
ndërsa (!F.eof())
//leximi i vlerës së radhës nga rrjedha F në ndryshoren a
F>>a;
//Nxjerr vlerën e ndryshores a në ekran
//rrit numrin e numrave të lexuar
//mbyllja e rrymës
F.close();
//fut në ekran numrin e numrave të lexuar
cout<<"n="<
//nëse hapja e skedarit ishte e pasaktë, atëherë dalja
//mesazhe për mungesën e një skedari të tillë
tjetër cout<<" Файл не существует"<
system ("pauzë");
kthimi 0;
C++. Përpunimi i skedarit binar
Kur shkruani informacion në një skedar binar, karakteret dhe numrat shkruhen si një sekuencë bajtash.
Në mënyrë që shkruani të dhënat në një skedar binar, ju nevojiten:
përshkruani një variabël skedari të tipit FAIL * duke përdorur operatorin FILE *filename;. Këtu emri i skedarit është emri i ndryshores ku do të ruhet treguesi i skedarit.
shkruani informacion në një skedar duke përdorur funksionin fwrite
Në mënyrë që numëroj b të dhëna nga një skedar binar, ju nevojiten:
përshkruani një variabël të tipit FILE *
hapni një skedar duke përdorur funksionin fopen
mbyllni një skedar duke përdorur funksionin fclose
Funksionet bazë të nevojshme për të punuar me skedarë binare.
Për zbulimet Skedari është menduar për funksionin fopen.
FILE *fopen (konst *emri i skedarit, konst char *modaliteti)
Këtu emri i skedarit është një varg që ruan emrin e plotë të skedarit që hapet, mod është një varg që përcakton mënyrën e punës me skedarin; vlerat e mëposhtme janë të mundshme:
"rb" - hapni skedarin binar në modalitetin e leximit;
"wb" - krijoni një skedar binar për regjistrim; nëse ekziston, përmbajtja e tij pastrohet;
"ab" - krijoni ose hapni një skedar binar për ta shtuar në fund të skedarit;
"rb+" - hapni një skedar binar ekzistues në modalitetin lexim-shkrim;
"wb+" - hapni skedarin binar në modalitetin e leximit-shkrimit, skedari ekzistues pastrohet;
"ab+" - hapet ose krijohet një skedar binar për të korrigjuar informacionin ekzistues dhe për të shtuar informacione të reja në fund të skedarit.
Funksioni kthen NULL në variablin e skedarit f nëse skedari hapet pa sukses. Pas hapjes së një skedari disponohet bajt i 0-të i tij, treguesi i skedarit është 0, vlera e të cilit, kur lexohet ose shkruhet, zhvendoset nga numri i bajteve të lexuara (të shkruara). Vlera aktuale e treguesit të skedarit është numri i bajtit nga i cili do të ndodhë operacioni i leximit ose i shkrimit.
Për mbyllja skedari është menduar për funksionin fclose
int fclose(FILE *emri i skedarit);
Kthen 0 nëse skedari është mbyllur me sukses, NULL ndryshe.
Funksioni i heqjes është për heqjen dosjet.
int remove(const char *filename);
Ky funksion fshin një skedar të quajtur filenema nga disku. Skedari që do të fshihet duhet të mbyllet. Funksioni kthen një vlerë jo zero nëse skedari nuk mund të fshihet.
Për riemërimi skedarët, funksioni i riemërtimit synohet:
int riemërto(const char *emri i vjetër i skedarit, const char *newfilename);
Parametri i parë është emri i vjetër i skedarit, i dyti është ai i ri. Kthen 0 nëse programi përfundon me sukses.
Leximi nga një skedar binar bëhet duke përdorur funksionin fread:
fread(void *ptr, madhësia, n, FILE *emri i skedarit);
Funksioni fread lexon n elementë të madhësisë nga emri i skedarit në një grup ptr. Funksioni kthen numrin e elementeve të lexuara. Pas leximit nga një skedar, treguesi i tij zhvendoset me bajt n*madhësi.
Regjistro në një skedar binar bëhet duke përdorur funksionin fwrite:
fwrite(const void *ptr, madhësia, n, FILE *emri i skedarit);
Funksioni fwrite shkruan në emrin e skedarit nga një grup ptr prej n elementësh të madhësisë. Funksioni kthen numrin e elementeve të shkruar. Pas shkrimit të informacionit në skedar, treguesi zhvendoset me bajt me madhësi n*.
Për kontrolli i fundit i skedarit ekziston një funksion feof:
int feof(FILE *emri i skedarit);
Ai kthen një vlerë jo zero nëse arrihet fundi i skedarit.
SHEMBULL:
Krijoni një skedar binar D:\\game\\noobs.dat dhe shkruani n numër të plotë dhe n numra realë në të.
#include "stdafx.h"
#përfshi
duke përdorur namespace std;
int main()
setlocale (LC_ALL, "RUS");
int n, i;
dyfishi a;
//krijoni një skedar binar në modalitetin e shkrimit
f=fopen("D:\\loja\\noobs.dat", "wb");
// hyrje numratn
cout<<"n="; cin>>n;
fwrite(&n, sizeof(int), 1, f);
//loop për të futur n numra realë
për (i=0; i
//fut numrin real të radhës
cout<<"a=";
cin>>a;
//shkrimi i një numri real në një skedar binar
fwrite(&a, sizeof(double), 1, f);
// mbyll dosje
fclose(f);
system ("pauzë");
kthimi 0;
SHEMBULL:
Shfaqni përmbajtjen e skedarit binar D:\\game\\noobs.dat të krijuar në detyrën e mëparshme
#include "stdafx.h"
#përfshi
duke përdorur namespace std;
int main()
setlocale (LC_ALL, "RUS");
int n, i;
dyfish *a;
FILE *f; //përshkruaj variablin e skedarit
//hap skedarin binar ekzistues në modalitetin e leximit
//lexoni një numër të plotë nga skedari në variablin n
//dalja n në ekran
cout<<"n="<
//ndarja e memories për një grup prej n numrash
a= dyfishi i ri[n];
//lexo n numra realë nga skedari në grup a
//Dalja e grupit në ekran
për (i=0; i
cout<
// mbyll dosje
fclose(f);
system ("pauzë");
kthimi 0;
Skedar binar- struktura sekuenciale e të dhënave, pas hapjes së një skedari, biti i parë i ruajtur në të është i disponueshëm. Ju mund të shkruani ose lexoni të dhëna nga një skedar në mënyrë sekuenciale. Le të themi se duhet të numëroni numrin e pesëmbëdhjetë, dhe më pas të parin. Duke përdorur aksesin sekuencial kjo mund të bëhet në mënyrën e mëposhtme:
int n, i;
dyfishi a;
FILE *f;
f=fopen("D:\\loja\\noobs.dat", "rb");
për (i=0; i<15; i++)
fclose(f);
f=fopen("D:\\loja\\noobs.dat", "rb");
fread(&a, madhësia e (dyfishtë), 1, f);
fclose(f);
Siç mund ta shihni, leximi i numrave nga një skedar dhe më pas hapja e skedarit përsëri nuk është mënyra më e përshtatshme. Do të jetë shumë më i përshtatshëm për të përdorur funksionin fseek për të zhvendosur treguesin e skedarit në një bajt të caktuar.
int fseek(FILE *emri i skedarit, zhvendosja e gjatë int, origjina int);
Funksioni vendos treguesin F të pozicionit aktual të skedarit në përputhje me vlerat e origjinës dhe të zhvendosjes. Parametri i kompensimit është i barabartë me numrin e bajteve me të cilat treguesi i skedarit do të kompensohet në lidhje me origjinën e specifikuar nga parametri i origjinës. Vlera për parametrin e origjinës duhet të jetë një nga vlerat e mëposhtme të kompensimit të përcaktuara në kokën stdio.h:
SEEK_SET - nga fillimi i skedarit;
SEEK_CUR - nga pozicioni aktual;
SEEK_END - nga fundi i skedarit.
Funksioni kthen një vlerë zero nëse operacioni ishte i suksesshëm, jo zero nëse ka ndodhur një dështim gjatë ekzekutimit të kompensimit
Funksioni fseek në të vërtetë zbaton qasje të drejtpërdrejtë në çdo vlerë në një skedar. Ju vetëm duhet të dini vendndodhjen (numrin e bajtit) të vlerës në skedar. Le të shohim përdorimin e aksesit të drejtpërdrejtë në skedarët binare duke përdorur problemin e mëposhtëm si shembull.
SHEMBULL
Në skedarin binar D:\\game\\noobs.dat të krijuar më parë, ndërroni numrat realë më të mëdhenj dhe më të vegjël.
Algoritmi për zgjidhjen e problemit përbëhet nga fazat e mëposhtme:
leximi i realeve nga një skedar në grup a.
kërkoni në grupin a për vlerat maksimale (max) dhe minimale (min) dhe numrat e tyre (imax, imin).
zhvendosja e treguesit të skedarit në vlerën maksimale dhe shkrimi min.
duke lëvizur treguesin e skedarit në vlerën minimale dhe duke shkruar max.
Më poshtë është teksti i programit për zgjidhjen e problemit me komente.
#include "stdafx.h"
#përfshi
duke përdorur namespace std;
int main()
setlocale (LC_ALL, "RUS");
int n, i, imax, imin;
dyfish *a, max, min;
FILE *f;
//hap një skedar në modalitetin lexim-shkrim
f=fopen("D:\\loja\\noobs.dat", "rb+");
//lexo numrin nga skedari në variablin n
//numrat realë në skedar
fread(&n, sizeof(int), 1, f);
cout<<"n="<
//alokoni memorien për ruajtjen e numrave realë,
//i cili do të ruhet në grup a
a= dyfishi i ri[n];
//lexo nga skedari në grup dhe numra realë
fread(a, madhësia e (dyfishtë), n, f);
//kërkimi për elementet maksimale dhe minimale
//në grupin a dhe indekset e tyre
për (imax=imin=0, max=min=a, i=1; i
nëse (a[i]> max)
max=a[i];
nëse (a[i]
min=a[i];
// duke lëvizur tregues për të maksimale element
fseek(f, sizeof(int)+imax*sizeof(double), SEEK_SET);
//shkruaj min në vend të elementit maksimal të skedarit
fwrite(&min, madhësia (dyfish), 1, f);
// duke lëvizur tregues për të minimale element
fseek(f, sizeof(int)+imin*sizeof(double), SEEK_SET);
//shkruaj max në vend të elementit minimal të skedarit
fwrite(&max, sizeof(double), 1, f);
//mbyllja e skedarit
fclose(f);
//lirimi i memories
fshij [ ]a;
system ("pauzë");
Etiketa: Skedarët e tekstit, fopen, fclose, feof, setbuf, setvbuf, flush, fgetc, fprintf, fscanf, fgets, transmetim me buffer, transmetim të pabuferuar.
Puna me skedarë teksti
Puna me një skedar teksti është e ngjashme me punën me tastierën: duke përdorur funksionet e hyrjes së formatuar ne ruajmë të dhënat në një skedar, duke përdorur funksionet e daljes së formatuar ne lexojmë të dhëna nga një skedar. Ka shumë nuanca që do t'i shikojmë më vonë. Operacionet kryesore që duhen bërë janë
- 1. Hapni skedarin në mënyrë që të mund të aksesohet. Prandaj, mund ta hapni atë për lexim, shkrim, lexim dhe shkrim, rishkrim ose shkrim deri në fund të skedarit, etj. Kur hapni një skedar, mund të ndodhin edhe një sërë gabimesh - skedari mund të mos ekzistojë, mund të jetë lloji i skedarit të gabuar, mund të mos keni leje për të punuar me skedarin, etj. E gjithë kjo duhet të merret parasysh.
- 2. Puna e drejtpërdrejtë me skedarin - shkrimi dhe lexim. Këtu duhet të kujtojmë gjithashtu se nuk po punojmë me memorie me akses të rastësishëm, por me një rrymë të buferuar, e cila shton specifikat e veta.
- 3. Mbyllni skedarin. Meqenëse skedari është një burim i jashtëm për programin, nëse nuk është i mbyllur, ai do të vazhdojë të qëndrojë në memorie, ndoshta edhe pasi programi të jetë mbyllur (për shembull, nuk do të jetë e mundur të fshini një skedar të hapur ose të bëni ndryshime, etj). Për më tepër, ndonjëherë është e nevojshme të mos mbyllni, por të "rihapni" një skedar në mënyrë që, për shembull, të ndryshoni mënyrën e hyrjes.
Përveç kësaj, ka një sërë detyrash kur nuk kemi nevojë të aksesojmë përmbajtjen e skedarit: riemërimi, zhvendosja, kopjimi, etj. Fatkeqësisht, standardi C nuk përmban një përshkrim të funksioneve për këto nevoja. Ato, natyrisht, janë të disponueshme për secilin prej zbatimeve të përpiluesit. Leximi i përmbajtjes së një drejtorie (dosje, direktori) është gjithashtu akses në një skedar, sepse vetë dosja është një skedar me metainformacion.
Ndonjëherë është e nevojshme të kryhen disa operacione ndihmëse: zhvendoseni në vendndodhjen e dëshiruar në skedar, mbani mend pozicionin aktual, përcaktoni gjatësinë e skedarit, etj.
Për të punuar me një skedar, ju nevojitet një objekt FILE. Ky objekt ruan identifikuesin e rrjedhës së skedarit dhe informacionin e nevojshëm për ta menaxhuar atë, duke përfshirë një tregues në buferin e tij, një tregues të pozicionit të skedarit dhe treguesit e statusit.
Objekti FILE është në vetvete një strukturë, por fushat e tij nuk duhet të aksesohen. Programi portativ duhet ta trajtojë skedarin si një objekt abstrakt që lejon aksesin në rrjedhën e skedarit.
Krijimi dhe shpërndarja e memories për një objekt të tipit FILE kryhet duke përdorur funksionin fopen ose tmpfile (ka të tjerë, por ne do të përqendrohemi vetëm në këto).
Funksioni fopen hap një skedar. Ai merr dy argumente - një varg me adresën e skedarit dhe një varg me mënyrën e hyrjes në skedar. Emri i skedarit mund të jetë absolut ose relativ. fopen kthen një tregues në një objekt FILE që mund të përdoret për të aksesuar më tej skedarin.
FILE* fopen(konst char* emri i skedarit, konst char* modaliteti);
Për shembull, le të hapim një skedar dhe të shkruajmë Hello World në të
#përfshi
Vetë funksioni fopen shpërndan memorie për objektin; pastrimi kryhet nga funksioni fclose. Është e nevojshme të mbyllet skedari; ai nuk do të mbyllet vetë.
Funksioni fopen mund të hapë një skedar në modalitetin tekst ose binar. Parazgjedhja është teksti. Mënyra e hyrjes mund të jetë si më poshtë
Lloji | Përshkrim |
---|---|
r | Leximi. Skedari duhet të ekzistojë. |
w | Shkruani një skedar të ri. Nëse një skedar me të njëjtin emër ekziston tashmë, përmbajtja e tij do të humbet. |
a | Shkruani deri në fund të skedarit. Operacionet e pozicionimit (fseek, fsetpos, frewind) nuk merren parasysh. Skedari krijohet nëse nuk ekziston. |
r+ | Leximi dhe përditësimi. Ju mund të lexoni dhe të shkruani. Skedari duhet të ekzistojë. |
w+ | Regjistrimi dhe përditësimi. Krijohet një skedar i ri. Nëse një skedar me të njëjtin emër ekziston tashmë, përmbajtja e tij do të humbet. Ju mund të shkruani dhe të lexoni. |
a+ | Përfundoni postimin dhe përditësimin. Operacionet e pozicionimit janë vetëm për lexim dhe injorohen për shkrime. Nëse skedari nuk ekziston, do të krijohet një i ri. |
Nëse është e nevojshme të hapni skedarin në modalitetin binar, atëherë shkronja b shtohet në fund të rreshtit, për shembull "rb", "wb", "ab", ose, për modalitetin e përzier, "ab+", " wb+”, “ab+”. Në vend të b, mund të shtoni shkronjën t, atëherë skedari do të hapet në modalitetin e tekstit. Varet nga zbatimi. Në standardin e ri C (2011), shkronja x do të thotë që fopen duhet të dështojë nëse skedari tashmë ekziston. Le të plotësojmë programin tonë të vjetër: rihapni skedarin dhe merrni parasysh atë që kemi shkruar atje.
#përfshi
Në vend të funksionit fgets, mund të përdorni fscanf, por duhet të mbani mend se ai mund të lexojë rreshtin vetëm deri në hapësirën e parë.
fscanf(skedar, "%127s", buffer);
Gjithashtu, në vend që të hapni dhe mbyllni një skedar, mund të përdorni funksionin freopen, i cili "rihap" skedarin me të drejta të reja aksesi.
#përfshi
Funksionet fprintf dhe fscanf ndryshojnë nga printf dhe scanf vetëm në atë që ata marrin si argument të parë një tregues të FILE-it në të cilin do të nxjerrin ose nga i cili do të lexojnë të dhëna. Vlen të shtohet menjëherë se funksionet printf dhe scanf mund të zëvendësohen lehtësisht nga funksionet fprintf dhe fscanf. Në OS (ne po shqyrtojmë sistemet operative më të zakonshme dhe adekuate) ekzistojnë tre rryma standarde: transmetimi standard i daljes stdout, transmetimi standard i hyrjes stdin dhe transmetimi standard i daljes së gabimit stderr. Ato hapen automatikisht kur hapet aplikacioni dhe lidhen me tastierën. Shembull
#përfshi
Gabim në hapjen e skedarit
Nëse thirrja e funksionit fopen dështon, ajo do të kthehet NULL. Gabimet gjatë punës me skedarë ndodhin mjaft shpesh, kështu që sa herë që hapim një skedar, duhet të kontrollojmë rezultatin e punës
#përfshi
Problemi lind kur hapen disa skedarë në të njëjtën kohë: nëse njëri prej tyre nuk mund të hapet, atëherë pjesa tjetër duhet të mbyllet gjithashtu.
FILE *inputFile, *outputFile; i panënshkruar m, n; i panënshkruar i, j; inputFile = hap (INPUT_FILE, VETËM LEXUAR); if (inputFile == NULL) ( printf("Gabim në hapjen e skedarit %s", INPUT_FILE); getch(); exit(3); ) outputFile = fopen(OUTPUT_FILE, WRITE_ONLY); if (outputFile == NULL) ( printf ("Gabim në hapjen e skedarit %s", OUTPUT_FILE); getch(); if (inputFile != NULL) ( fclose(inputFile); ) dalje (4); ) ...
Në raste të thjeshta, mund të veproni kokë më kokë, si në pjesën e mëparshme të kodit. Në raste më komplekse, përdoren metoda që zëvendësojnë RAII nga C++: mbështjellësit, ose veçoritë e përpiluesit (pastrimi në GCC), etj.
Buferimi i të dhënave
Siç u përmend më herët, kur nxjerrim të dhëna, ato fillimisht vendosen në një buffer. Buferi është pastruar
- 1) Nëse është plot
- 2) Nëse rryma është e mbyllur
- 3) Nëse tregojmë në mënyrë eksplicite se është e nevojshme të pastrohet buffer (ka përjashtime edhe këtu :)).
- 4) Gjithashtu pastrohet nëse programi përfundoi me sukses. Në të njëjtën kohë, të gjitha dosjet mbyllen. Në rast të një gabimi në kohën e ekzekutimit, kjo mund të mos ndodhë.
Ju mund të detyroni shkarkimin e buferit duke thirrur funksionin flush(File *). Le të shohim dy shembuj - me dhe pa pastrim.
#përfshi
Hiq komentin e thirrjes flush. Në kohën e ekzekutimit, hapni skedarin e tekstit dhe shikoni sjelljen.
Ju mund të caktoni vetë një buffer skedari duke vendosur madhësinë tuaj. Kjo bëhet duke përdorur funksionin
Void setbuf (FILE * stream, char * buffer);
i cili merr një FILE tashmë të hapur dhe një tregues në një buffer të ri. Madhësia e tamponit të ri duhet të jetë jo më pak se BUFSIZ (për shembull, në stacionin aktual të punës BUFSIZ është 512 bajt). Nëse kaloni NULL si bufer, transmetimi bëhet i pabuferuar. Ju gjithashtu mund të përdorni funksionin
Int setvbuf(FILE * stream, char * buffer, int mode, size_t size);
e cila pranon një tampon me madhësi arbitrare. Modaliteti mund të marrë vlerat e mëposhtme
- _IOFBF- buffering i plotë. Të dhënat shkruhen në skedar kur është plot. Pas leximit, buferi konsiderohet i plotë kur kërkohet një operacion hyrës dhe buferi është bosh.
- _IOLBF- buffering linear. Të dhënat shkruhen në skedar kur ai është i plotë ose kur haset një karakter i linjës së re. Pas leximit, buferi mbushet me karakterin e linjës së re kur kërkohet një operacion hyrës dhe buferi është bosh.
- _IONBF– pa buferim. Në këtë rast, madhësia dhe parametrat e tamponit injorohen.
Shembull: le të vendosim bufferin tonë dhe të shohim se si kryhet leximi nga një skedar. Le të jetë skedari i shkurtër (diçka si Hello, World!), dhe ne e lexojmë atë karakter pas karakter
#përfshi
Mund të shihet se të dhënat janë tashmë në tampon. Leximi karakter për karakter bëhet nga buferi.
feof
Funksioni int feof(FILE * stream); kthehet true nëse arrihet fundi i skedarit. Funksioni është i përshtatshëm për t'u përdorur kur duhet të kaloni të gjithë skedarin nga fillimi në fund. Le të ketë një skedar me përmbajtje teksti text.txt. Ne lexojmë skedarin karakter për karakter dhe e shfaqim atë në ekran.
#përfshi
Gjithçka do të ishte mirë, por funksioni feof nuk funksionon si duhet... Kjo për faktin se koncepti "fundi i skedarit" nuk është i përcaktuar. Një gabim që ndodh shpesh kur përdorni feof është se të dhënat e fundit të lexuara printohen dy herë. Kjo për faktin se të dhënat shkruhen në buferin e hyrjes, leximi i fundit ndodh me një gabim dhe funksioni kthen vlerën e vjetër të lexuar.
#përfshi
Ky shembull do të dështojë (ka shumë të ngjarë) dhe do të printojë karakterin e fundit të skedarit dy herë.
Zgjidhja është të mos përdorni feof. Për shembull, ruani numrin total të regjistrimeve ose përdorni faktin që funksionet fscanf etj. zakonisht kthejnë numrin e vlerave të lexuara dhe të përputhura saktë.
#përfshi
Shembuj
1. Një skedar përmban dy numra - dimensionet e grupit. Le të mbushim skedarin e dytë me një grup numrash të rastit.
#përfshi
2. Përdoruesi kopjon skedarin dhe së pari zgjedh mënyrën e funksionimit: skedari mund të dalë ose në tastierë ose të kopjohet në një skedar të ri.
#përfshi
3. Përdoruesi fut të dhënat nga tastiera dhe shkruhet në një skedar derisa të shtypet tasti esc. Shikoni programin dhe shikoni. si sillet nëse futni hapësirën e pasme: çfarë del në skedar dhe çfarë del në tastierë.
#përfshi
4. Skedari përmban numra të plotë. Gjeni maksimumin prej tyre. Le të përfitojmë nga fakti që funksioni fscanf kthen numrin e objekteve të lexuara dhe të përputhura saktë. Numri 1 duhet të kthehet çdo herë.
#përfshi
Një zgjidhje tjetër është leximi i numrave derisa të arrijmë në fund të skedarit.
#përfshi
5. Skedari përmban fjalët: fjalë ruse, tabela, fjalë angleze, në disa rreshta. Përdoruesi fut një fjalë angleze, është e nevojshme të nxirret ajo ruse.
Skedari i përkthimit duket diçka si kjo
dielli i diellit
stilolaps laps
laps me stilolaps
dera e derës
dritare e dritareve
karrige karrige
kolltuk
dhe ruhet në kodimin cp866 (OEM 866). Është e rëndësishme: çifti i fundit i fjalëve përfundon gjithashtu me një furnizim rreshti.
Algoritmi është si më poshtë: ne lexojmë një rresht nga një skedar, gjejmë një karakter skedë në rresht, zëvendësojmë karakterin e skedës me një zero, kopjojmë një fjalë ruse nga buferi, kopjojmë një fjalë angleze nga tampon, kontrollojmë për barazi.
#përfshi
6. Numëroni numrin e rreshtave në skedar. Do ta lexojmë skedarin karakter për karakter, duke numëruar numrin e karaktereve "\n" derisa të hasim karakterin EOF. EOF është një karakter i veçantë që tregon se hyrja është e plotë dhe nuk ka më të dhëna për të lexuar. Funksioni kthen një vlerë negative në rast gabimi.
SHËNIM: EOF është i tipit int, kështu që ju duhet të përdorni int për të lexuar karakteret. Për më tepër, vlera e EOF nuk është e përcaktuar me standard.
#define _CRT_SECURE_NO_WARNINGS #include
Ru-Cyrl 18-tutorial Sypachev S.S. 1989-04-14 [email i mbrojtur] Stepan Sypachev nxënësit
Ende nuk është e qartë? – shkruani pyetje në kutinë postare