Fungovanie I/O súboru v C++ je takmer rovnaké ako bežné I/O (ale s niekoľkými nuansami).
Súbor I/O tried
Existuje tri hlavné triedy I/O súborov v C++:
mimo prúdu(je dieťaťom triedy);
fstream(je dieťaťom triedy iostream).
Pomocou týchto tried môžete vykonávať jednosmerný vstup súboru, jednosmerný výstup súboru a obojsmerný vstup/výstup súboru. Ak ich chcete použiť, stačí pripojiť fstream.
Na rozdiel od streamov cout, cin, cerr a clog, ktoré sú okamžite použiteľné, toky súborov musí explicitne nastaviť programátor. To znamená, že ak chcete otvoriť súbor na čítanie a/alebo zápis, musíte vytvoriť objekt príslušnej I/O triedy súboru, pričom ako parameter uvediete názov súboru. Potom pomocou operátorov vkladania (<<) или извлечения (>>), môžete zapisovať údaje do súboru alebo čítať obsah súboru. Potom konečná - musíte súbor zavrieť: výslovne zavolať close() metóda alebo jednoducho nechajte premennú I/O súboru mimo rozsahu (trieda I/O súboru za nás tento súbor automaticky zatvorí).
Výstup súboru
Trieda ofstream sa používa na zápis do súboru. Napríklad:
#include
#include #include #include int main() pomocou menného priestoru std ; // ofstream sa používa na zapisovanie údajov do súboru // Vytvorenie súboru SomeText.txt ofstream outf("SomeText.txt" ) ; // Ak nemôžeme tento súbor otvoriť, aby sme doň zapísali údaje ak(!outf) // Potom vytlačte chybové hlásenie a spustite exit() cerr<< << endl ; exit(1) ; // Do súboru zapíšeme nasledujúce dva riadky outf<< "See line #1!" << endl ; outf<< "See line #2!" << endl ; návrat 0; // Keď outf prekročí rozsah, deštruktor triedy ofstream automaticky zatvorí náš súbor |
Ak sa pozriete do adresára projektu ( RMB na karte s názvom vášho súboru .cpp vo Visual Studiu > "Otvoriť priečinok obsahujúci"), uvidíte súbor s názvom SomeText.txt, ktorý obsahuje nasledujúce riadky:
Pozri riadok #1!
Pozri riadok #2!
Upozorňujeme, že môžeme použiť aj put() metóda na zapísanie jedného znaku do súboru.
Vstup súboru
#include
#include #include #include #include int main() pomocou menného priestoru std ; // ifstream sa používa na čítanie obsahu súboru // Ak nemôžeme tento súbor otvoriť a prečítať si jeho obsah if(!inf) // Potom vytlačte nasledujúce chybové hlásenie a spustite exit() cerr<< << endl ; exit(1) ; // Pokiaľ existujú údaje, ktoré môžeme čítať while(inf) // Potom tieto údaje presunieme do reťazca, ktorý následne zobrazíme na obrazovke string strInput ; inf >> strInput ; cout<< strInput << endl ; návrat 0; // Keď inf prekročí rozsah, deštruktor triedy ifstream automaticky zatvorí náš súbor |
Pozri
riadok
#1!
Pozri
riadok
#2!
Hmm, nie je to celkom to, čo sme chceli. Ako už vieme z predchádzajúcich lekcií, operátor extrakcie pracuje s „formátovanými dátami“, t.j. ignoruje všetky medzery, tabulátory a nové riadky. Na čítanie celého obsahu tak, ako je, bez jeho rozdelenia na časti (ako v príklade vyššie), musíme použiť metóda getline().:
#include
#include #include #include #include int main() pomocou menného priestoru std ; // ifstream sa používa na čítanie obsahu súborov ifstream inf("NiejakyText.txt" ) ; // Ak nemôžeme otvoriť súbor, aby sme si prečítali jeho obsah if(!inf) // Potom vytlačte nasledujúce chybové hlásenie a spustite exit() cerr<< "Och, SomeText.txt sa nepodarilo otvoriť na čítanie!"<< endl ; exit(1) ; while(inf) string strInput ; getline (inf , strInput ) ; cout<< strInput << endl ; návrat 0; // Keď inf prekročí rozsah, deštruktor triedy ifstream automaticky zatvorí náš súbor |
Výsledkom spustenia vyššie uvedeného programu je:
výstup s vyrovnávacou pamäťou
Výstup v C++ je možné uložiť do vyrovnávacej pamäte. To znamená, že všetko, čo je na výstupe do prúdového súboru súborov, nemôže byť okamžite zapísané na disk (do konkrétneho súboru). Deje sa tak predovšetkým z výkonnostných dôvodov. Keď sa dáta vyrovnávacej pamäte zapisujú na disk, volá sa to čistenie vyrovnávacej pamäte. Jedným zo spôsobov, ako vyčistiť vyrovnávaciu pamäť, je zatvoriť súbor. V tomto prípade sa celý obsah vyrovnávacej pamäte presunie na disk a potom sa súbor zatvorí.
Výstupná vyrovnávacia pamäť zvyčajne nie je problémom, ale za určitých okolností môže spôsobiť problémy neopatrným nováčikom. Napríklad, keď sú dáta uložené vo vyrovnávacej pamäti a program predčasne ukončí ich vykonávanie (buď v dôsledku zlyhania alebo volaním ). V takýchto prípadoch sa deštruktory tried I/O súborov nevykonajú, súbory sa nikdy nezatvoria, vyrovnávacie pamäte sa nevyprázdnia a naše údaje sa navždy stratia. Preto je dobré pred volaním exit() explicitne zatvoriť všetky otvorené súbory.
Vyrovnávaciu pamäť môžete vymazať aj manuálne pomocou ostream::flush() metóda alebo odoslaním std::flush do výstupného prúdu. Ktorákoľvek z týchto metód môže byť užitočná na zabezpečenie okamžitého zápisu obsahu vyrovnávacej pamäte na disk v prípade zlyhania programu.
Zaujímavá nuansa: Pretože std::endl; tiež vymaže výstupný tok, jeho nadmerné používanie (vedúce k zbytočnému vyprázdneniu vyrovnávacej pamäte) môže ovplyvniť výkon programu (pretože vyprázdnenie vyrovnávacej pamäte môže byť v niektorých prípadoch drahé). Z tohto dôvodu programátori, ktorí dbajú na výkon, často používajú \n namiesto std::endl na vloženie znaku nového riadku do výstupného toku, aby sa vyhli zbytočnému preplachovaniu vyrovnávacej pamäte.
Režimy otvárania súborov
Čo sa stane, ak sa pokúsime zapísať údaje do už existujúceho súboru? Opätovné spustenie programu vyššie (úplne prvý) ukazuje, že pôvodný súbor je pri opätovnom spustení programu úplne prepísaný. Čo ak však potrebujeme pridať údaje na koniec súboru? Ukázalo sa, že tok súboru má voliteľný druhý parameter, ktorý vám umožňuje povedať programátorovi, ako má súbor otvoriť. Ako tento parameter môžete prejsť nasledujúce vlajky(ktoré sú v triede ios):
aplikácie- otvorí súbor v režime pripojenia;
jedol- prejde na koniec súboru pred čítaním/zápisom;
binárne- otvorí súbor v binárnom režime (namiesto textového režimu);
v- otvorí súbor v režime čítania (predvolené pre ifstream);
von- otvorí súbor v režime zápisu (predvolené pre ofstream);
trunc- vymaže súbor, ak už existuje.
Môžete zadať viacero príznakov naraz pomocou .
ifstream štandardne funguje v režime ios::in;
ofstream štandardne funguje v režime ios::out;
fstream štandardne beží v režime ios::in OR ios::out, čo znamená, že môžete čítať obsah súboru alebo zapisovať údaje do súboru.
Teraz napíšme program, ktorý pridá dva riadky do predtým vytvoreného súboru SomeText.txt:
#include
#include #include #include int main() pomocou menného priestoru std ; // Odovzdaním príznaku ios:app oznámime fstreamu, že svoje údaje pridáme k už existujúcim údajom súboru, // súbor neprepíšeme. Nepotrebujeme odovzdať príznak ios::out, // pretože ofstream je štandardne nastavený na režim ios::out ofstream outf("SomeText.txt" , ios::app ) ; // Ak nemôžeme otvoriť súbor na zápis údajov ak(!outf) // Potom vytlačte nasledujúce chybové hlásenie a spustite exit() cerr<< "Och, SomeText.txt sa nepodarilo otvoriť na zápis!"<< endl ; exit(1) ; |
Mechanizmus I/O vyvinutý spoločnosťou , nezodpovedá dnes všeobecne akceptovanému štýlu objektovo orientovaného programovania, navyše aktívne využíva operácie ukazovateľov, ktoré sú v moderných prostrediach vykonávania bezpečného kódu považované za potenciálne nebezpečné. Alternatívou pre vývoj aplikácií je štandardný mechanizmus I/O tried poskytovaný štandardom jazyka C++.
Otváranie súborov
Najčastejšie používané triedy sú ifstream na čítanie, ofstream na zápis a fstream na úpravu súborov.
Všetky vlákna I/O triedy sú nepriamo odvodené od spoločného predka ios, pričom plne zdedia jeho funkčnosť. Napríklad enumerovaný dátový člen open_mode špecifikuje režim otvárania súboru, ktorý je definovaný takto:
Enum open_mode ( app, binary, in, out, trunc, ate );
Nižšie sú uvedené možné hodnoty vlajok a ich účel.
Ak chcete napríklad otvoriť súbor s názvom test.txt na čítanie binárnych údajov, napíšte:
súbor ifstream; file.open("test.txt", ios::in | ios::binary);
Logický operátor OR (|) vám umožňuje zostaviť režim s ľubovoľnou kombináciou príznakov. Aby ste pri otváraní súboru zápisom omylom neprepísali existujúci súbor s rovnakým názvom, musíte použiť nasledujúci formulár:
offstream súbor; file.open("test.txt", ios::out | ios::app);
Predpokladá sa, že príslušný hlavičkový súbor je pripojený k projektu:
#include
Ak chcete skontrolovať, či bol súbor úspešne otvorený, môžete použiť konštrukciu
If (!file) ( // Spracovanie chyby pri otvorení súboru )
Operátori inklúzie a ťažby
Prepísané v triedach spracovania súborov zahŕňať operátora (<<) записывает данные в файловый поток. Как только вы открыли файл для записи, можно записывать в него текстовую строку целиком:
súbor<< "Это строка текста";
Textový reťazec môžete napísať aj po častiach:
súbor<< "Это " << "строка " << "текста";
Príkaz endl ukončí vstup riadku návratom vozíka:
súbor<< "Это строка текста" << endl;
Pomocou operátora include je ľahké zapísať hodnoty premenných alebo prvkov poľa do súboru:
Ofstream súbor("Temp.txt"); char buff = "Textové pole obsahuje premenné"; int vx = 100; float pi = 3,14159; súbor<< buff << endl << vx << endl << pi << endl;
V dôsledku spustenia kódu sa vygenerujú tri riadky textového súboru Temp.txt:
Textové pole obsahuje premenné 100 3,14159
Všimnite si, že číselné hodnoty sa do súboru zapisujú ako textové reťazce, nie binárne hodnoty.
operátor extraktu(>>) robí pravý opak. Zdá sa, že ak chcete extrahovať znaky zo súboru Temp.txt napísaného skôr, musíte napísať kód, ako je tento:
ifstream súbor("Temp.txt"); char buff; intvx; floatpi; súbor >> buff >> vx >> pi;
Operátor extrakcie sa však zastaví pri prvom oddeľovači (medzera, tabulátor alebo nový riadok), na ktorý narazí. Pri analýze vety „Textové pole obsahuje premenné“ sa teda do poľa buff zapíše iba slovo „Text“, medzera sa ignoruje a slovo „pole“ sa stane hodnotou celočíselnej premennej vx a kódu exekúcia sa „zničí“ s nevyhnutným porušením štruktúry údajov. Ďalej si pri diskusii o triede ifstream ukážeme, ako správne zorganizovať čítanie súboru z predchádzajúceho príkladu.
trieda ifstream: čítanie súborov
Ako už názov napovedá, trieda ifstream je navrhnutá na vstup dátového toku súboru. Hlavné metódy triedy sú uvedené nižšie. Väčšina z nich je zdedená z triedy istream a preťažená nadradenou funkcionalitou. Napríklad funkcia get v závislosti od parametra volania dokáže prečítať nielen jeden znak, ale aj blok znakov.
Teraz je jasné, ako musíte upraviť predchádzajúci príklad, aby použitie operátora extrakcie údajov poskytlo očakávaný výsledok:
ifstream súbor("Temp.txt"); char buff; intvx; floatpi; file.getline(buff, sizeof(buff)); súbor >> vx >> pi:
Metóda getline prečíta prvý riadok súboru až do konca a operátor >> priradí hodnoty premenným.
Nasledujúci príklad ukazuje pridávanie údajov do textového súboru a následné čítanie celého súboru. Cyklus while (1) sa používa namiesto while(!file2.eof()) z dôvodov uvedených v .
#include
Nasledujúci príklad prechádza čítaním riadkov zo súboru test.txt a ich zobrazením na konzole.
#include
Tento kód pod OS Windows závisí aj od prítomnosti znaku nového riadku v poslednom riadku súboru, spoľahlivejšie by bolo:
While (1) ( if (file.eof()) break; file.getline(str, sizeof(str)); cout<< str << endl; }
Explicitné volania metód otvorenia a zatvorenia sú voliteľné. Volanie konštruktora s argumentom vám skutočne umožňuje otvoriť súbor okamžite, v momente, keď je vytvorený objekt streamu súboru:
ifstream súbor("test.txt");
Namiesto metódy close môžete použiť operátor delete, ktorý automaticky zavolá deštruktor súborového objektu a zatvorí súbor. Kód cyklu while poskytuje správnu kontrolu konca súboru.
ofstream trieda: písanie súborov
Trieda ofstream je navrhnutá na výstup údajov zo súborového toku. Hlavné metódy tejto triedy sú uvedené nižšie.
Operátor include opísaný vyššie je vhodný na organizáciu zápisu do textového súboru:
Ofstream súbor("temp.txt"); if (!file) return; pre (int i=1; i<=3; i++) file << "Строка " << i << endl; file.close();
Binárne súbory
V zásade sa binárne dáta obsluhujú ako textové dáta. Rozdiel je v tom, že ak sú binárne dáta zapísané v určitej logickej štruktúre, potom sa musia zo súboru načítať do premennej rovnakého typu štruktúry.
Prvý parameter metód zápisu a čítania (adresa bloku zápisu/čítania) musí byť typu znakového ukazovateľa char * , preto je potrebné explicitne previesť typ adresy štruktúry void *. Druhý parameter určuje, že binárne bloky súboru majú konštantnú veľkosť bajtov bez ohľadu na skutočnú dĺžku záznamu. V nasledujúcom dodatku je uvedený príklad vytvárania a zobrazovania údajov v jednoduchom poznámkovom bloku. Záznamy súboru sa potom načítajú postupne a zobrazia sa na konzole.
#include
V dôsledku vykonania tohto kódu sa vytvorí binárny súbor Notebook.dat z troch blokov po 80 bajtov (za predpokladu, že znaky sú jednobajtové). Prirodzene, môžete použiť aj iné metódy streamovania a vykonávať akúkoľvek operáciu na poliach konkrétnej dátovej štruktúry.
trieda fstream: náhodný prístup k súborom
Predpokladajme, že náš zápisník má nazhromaždených 100 záznamov a my chceme napočítať 50. Samozrejme, môžete usporiadať slučku a prečítať všetky záznamy od prvého po daný. Je zrejmé, že cielenejším riešením je nastaviť ukazovateľ polohy súboru POS priamo na záznam 50 a prečítať ho:
ifstream ifile("Notebook.dat", ios::binary); int pos = 49 * sizeof(Notes); ifile find(pos); // hľadanie 50. položky Poznámky Poznámka; //Poznámky - štruktúra "záznam" popísaná vyššie ifile.read((char*)&Note, sizeof(Notes));
Takéto operácie vyhľadávania sú účinné, ak súbor pozostáva zo záznamov známej a konštantnej veľkosti. Ak chcete nahradiť obsah ľubovoľnej položky, musíte otvoriť výstupný tok v režime úprav:
Ofstream ofile("Notebook.dat", ios::binary | ios::ate); int pos = 49 * sizeof(Notes); ofile seekp(pos); // hľadanie 50. noty Notes Note50 = ("Jeľcin Boris Nikolajevič", "095-222-3322", 64); ofile.write((znak*)&Poznámka, veľkosť(Poznámky)); // výmena
Ak nešpecifikujete príznak ios::ate (alebo ios::app), potom pri otvorení binárneho súboru Notebook.dat bude jeho predchádzajúci obsah vymazaný!
Nakoniec je možné otvoriť súbor súčasne na čítanie/zápis pomocou metód zdedených triedou streamovania fstream od svojich predchodcov. Keďže trieda fstream je odvodená od istream a ostream (rodičov ifstream a ofstream), všetky vyššie uvedené metódy sú dostupné pre aplikáciu.
Nasledujúci príklad zamieňa prvú a tretiu položku v súbore Notebook.dat.
#include
Príznaky ios::in a ios::out musia byť špecifikované v konštruktore súborového objektu, aby sa umožnili súbežné operácie čítania a zápisu. V dôsledku vykonania tohto kódu dôjde k zámene prvého a tretieho záznamu binárneho súboru Notebook.dat.
K téme sú aj ďalšie príklady.
Väčšina počítačových programov pracuje so súbormi, a preto je potrebné súbory vytvárať, mazať, zapisovať, čítať, otvárať. Čo je súbor? Súbor je pomenovaná kolekcia bajtov, ktorá môže byť uložená na nejakom úložnom zariadení. Teraz je jasné, že súbor je nejaká sekvencia bajtov, ktorá má svoj vlastný jedinečný názov, ako napríklad súbor .txt. Súbory s rovnakým názvom nemôžu byť v rovnakom adresári. Názov súboru sa chápe nielen ako jeho názov, ale aj ako prípona, napríklad: súbor.txt a súbor.dat — rôzne súbory, hoci majú rovnaký názov. Existuje niečo ako úplný názov súborov - je to úplná adresa do adresára súboru s názvom súboru, napríklad: D:\docs\file.txt . Je dôležité pochopiť tieto základné pojmy, inak bude ťažké pracovať so súbormi.
Ak chcete pracovať so súbormi, musíte zahrnúť súbor hlavičky
Súborový I/O je podobný štandardnému I/O, jediný rozdiel je v tom, že I/O sa nerobí na obrazovke, ale do súboru. Ak sa vstup/výstup na štandardné zariadenia vykonáva pomocou objektov cin a cout, potom na organizáciu I/O súboru stačí vytvoriť vlastné objekty, ktoré sa dajú použiť podobne ako operátory cin a cout.
Napríklad musíte vytvoriť textový súbor a napísať doň riadok Práca so súbormi v C++. Ak to chcete urobiť, musíte vykonať nasledujúce kroky:
- vytvoriť objekt triedy prúdu ;
- priradiť objekt triedy k súboru, do ktorého sa má zapisovať;
- napísať riadok do súboru;
- zatvorte súbor.
Prečo je potrebné vytvoriť objekt triedy ofstream a nie triedy ifstream? Pretože potrebujete zapisovať do súboru a ak by ste potrebovali čítať údaje zo súboru, potom by sa vytvoril objekt triedy ifstream.
// vytvorte objekt na zápis do súboru ofstream /*názov objektu*/; // objekt triedy prúdu
Nazvime objekt - fout , Tu je to, čo sa stane:
Ofstream fout;
Prečo potrebujeme predmet? Objekt musí byť schopný zapisovať do súboru. Objekt už bol vytvorený, ale nie je priradený k súboru, do ktorého sa má reťazec zapísať.
fout.open("cppstudio.txt"); // priradiť objekt k súboru
Operáciou bodka získame prístup k metóde triedy open(), v ktorej zátvorke uvádzame názov súboru. Zadaný súbor sa vytvorí v aktuálnom adresári s programom. Ak existuje súbor s rovnakým názvom, existujúci súbor bude nahradený novým. Súbor je teda otvorený, zostáva doň napísať požadovaný riadok. Robí sa to takto:
Fout<< "Работа с файлами в С++"; // запись строки в файл
Pomocou operácie cast to stream v spojení s objektom fout sa reťazec File Handling v C++ zapíše do súboru. Keďže už nie je potrebné meniť obsah súboru, musí byť uzavretý, to znamená, že objekt by mal byť oddelený od súboru.
fout.close(); // zatvorte súbor
V dôsledku toho bol vytvorený súbor s riadkom Práca so súbormi v C++.
Kroky 1 a 2 je možné kombinovať, to znamená vytvoriť objekt v jednom riadku a priradiť ho k súboru. Robí sa to takto:
Ofstream fout("cppstudio.txt"); // vytvoríme objekt triedy ofstream a priradíme ho k súboru cppstudio.txt
Skombinujme celý kód a získame nasledujúci program.
// file.cpp: definuje vstupný bod pre aplikáciu konzoly. #include "stdafx.h" #include
Zostáva skontrolovať správnu činnosť programu, a preto súbor otvoríme cppstudio.txt a pozrite sa na jeho obsah, malo by to byť - Práca so súbormi v C++.
- vytvorte objekt triedy ifstream a priraďte ho k súboru, z ktorého sa má čítať;
- čítať súbor;
- zatvorte súbor.
Program ukazuje dva spôsoby čítania zo súboru, prvým je použitie operácie prenosu do prúdu, druhým je použitie funkcie getline() . V prvom prípade sa číta iba prvé slovo a v druhom prípade sa číta reťazec 50 znakov. Ale keďže v súbore zostáva menej ako 50 znakov, znaky sa čítajú až po posledný vrátane. Všimnite si, že čítanie druhýkrát (riadok 17) pokračoval po prvom slove a nie od začiatku, pretože prvé slovo bolo prečítanériadok 14. Výsledok programu je znázornený na obrázku 1.
Práca so súbormi v C++ Pokračujte stlačením ľubovoľného klávesu. . .
Obrázok 1 - Práca so súbormi v C++
Program fungoval správne, ale nie vždy to tak je, aj keď je s kódom všetko v poriadku. Programu bol odovzdaný napríklad názov neexistujúceho súboru alebo sa v názve vyskytla chyba. Čo potom? V tomto prípade sa nestane vôbec nič. Súbor sa nenájde, čo znamená, že ho nie je možné prečítať. Preto bude kompilátor ignorovať riadky, kde sa so súborom manipuluje. V dôsledku toho sa program ukončí správne, ale na obrazovke sa nič nezobrazí. Zdalo by sa, že je to úplne normálna reakcia na takúto situáciu. Jednoduchý používateľ však nepochopí, o čo ide a prečo sa na obrazovke neobjavil riadok zo súboru. Takže, aby bolo všetko veľmi jasné, C++ poskytuje takúto funkciu - is_open() , ktorá vracia celočíselné hodnoty: 1 - ak bol súbor úspešne otvorený, 0 - ak súbor nebol otvorený. Dokončite program otvorením súboru tak, že ak sa súbor neotvorí, zobrazí sa zodpovedajúca správa.
// file_read.cpp: definuje vstupný bod pre aplikáciu konzoly. #include "stdafx.h" #include
Výsledok programu je znázornený na obrázku 2.
Súbor sa nedá otvoriť! Pre pokračovanie stlačte ľubovolnú klávesu. . .
Obrázok 2 - Práca so súbormi v C++
Ako môžete vidieť na obrázku 2, program hlásil, že súbor nie je možné otvoriť. Preto, ak program pracuje so súbormi, odporúča sa použiť túto funkciu is_open() , aj keď ste si istí, že súbor existuje.
Režimy otvárania súborov
Režimy otvárania súborov určujú, ako sa súbory používajú. Na nastavenie režimu poskytuje trieda ios_base konštanty, ktoré určujú režim otvárania súboru (pozri tabuľku 1).
Režimy otvárania súborov je možné nastaviť priamo pri vytváraní objektu alebo pri volaní funkcie open(). .
Ofstream fout("cppstudio.txt", ios_base::app); // otvorenie súboru na pridanie informácií na koniec súboru fout. open("cppstudio.txt", ios_base::app); // otvorenie súboru na pridanie informácií na koniec súboru
Režimy otvárania súboru je možné kombinovať pomocou bitovej booleovskej operácie alebo| , napríklad: ios_base::out | ios_base::trunc - otvorenie súboru na zápis po jeho vymazaní.
Objekty triedy ofstream , keď sú spojené so súbormi, štandardne obsahujú režimy otvárania súborov ios_base::out | ios_base::trunc . To znamená, že súbor sa vytvorí, ak neexistuje. Ak súbor existuje, jeho obsah bude vymazaný a samotný súbor bude pripravený na nahrávanie. Objekty triedy ifstream, keď sú spojené so súborom, majú štandardne režim otvárania súboru ios_base::in - súbor je otvorený len na čítanie. Režim otvárania súboru sa nazýva aj príznak, kvôli čitateľnosti budeme tento výraz používať aj v budúcnosti. Tabuľka 1 neuvádza všetky príznaky, ale na začiatok by vám mali stačiť.
Upozorňujeme, že príznaky ate a app sú veľmi podobné v popise, oba posúvajú ukazovateľ na koniec súboru, ale príznak app umožňuje zapisovať iba na koniec súboru a príznak ate jednoducho preusporiada príznak na koniec súboru a neobmedzuje priestor pre záznam.
Vytvorme program, ktorý pomocou operácie sizeof() vypočíta charakteristiky hlavných dátových typov v C++ a zapíše ich do súboru. Charakteristika:
- počet bajtov pridelených pre dátový typ
- maximálnu hodnotu, ktorú môže konkrétny typ údajov uložiť.
Zápis do súboru musí byť v nasledujúcom formáte:
/* dátový typ bajtov maximálna hodnota bool = 1 255,00 char = 1 255,00 krátka int = 2 32767,00 nepodpísané krátke int = 2 65535,00 int = 4 2147483647,00 nepodpísané int = 4 42949675,00 Long Int = 4 2147,00 dlhý plavák = 8 9223372036854775800,00 double = 8 9223372036854775800,00 */
Takýto program už bol vyvinutý skôr v tejto časti, ale tam boli všetky informácie o typoch údajov vyvedené na štandardné výstupné zariadenie a musíme program prerobiť tak, aby sa informácie zapisovali do súboru. Ak to chcete urobiť, musíte súbor otvoriť v režime zápisu s predbežným skrátením informácií o aktuálnom súbore ( riadok 14). Po vytvorení a úspešnom otvorení súboru (riadky 16 - 20) namiesto príkazu cout v riadok 22 použiť predmet fout. teda namiesto obrazovky sa do súboru zapíšu informácie o typoch údajov.
// write_file.cpp: definuje vstupný bod pre aplikáciu konzoly. #include "stdafx.h" #include
Nemožno si nevšimnúť, že zmeny v programe sú minimálne a to všetko vďaka tomu, že štandardný vstup/výstup a súborový vstup/výstup sa používajú úplne rovnakým spôsobom. Na konci programuriadok 45súbor sme výslovne uzavreli, aj keď sa to nevyžaduje, považuje sa to za dobrú programátorskú prax. Stojí za zmienku, že všetky funkcie a manipulátory používané na formátovanie štandardného vstupu/výstupu sú relevantné aj pre vstup/výstup súboru. Pri operátorovi sa teda nevyskytli žiadne chyby cout bol nahradený objektom fout.
Posledná aktualizácia: 31.10.2015
Na prácu s adresármi v mennom priestore System.IO sú navrhnuté dve triedy: Directory a DirectoryInfo .
Adresárová trieda
Trieda Directory poskytuje množstvo statických metód na správu adresárov. Niektoré z týchto metód sú:
CreateDirectory(cesta) : vytvorí adresár na zadanej ceste
Delete(path) : vymaže adresár na danej ceste
Existuje(cesta) : Určuje, či adresár na zadanej ceste existuje. Ak existuje, vráti hodnotu true, ak nie, vráti hodnotu false.
GetDirectories(cesta) : Získa zoznam adresárov v ceste
GetFiles(path) : Získa zoznam súborov v adresárovej ceste
Move(sourceDirName, destDirName): presunie adresár
GetParent(path) : získa nadradený adresár
Trieda DirectoryInfo
Táto trieda poskytuje funkcie na vytváranie, odstraňovanie, presúvanie a iné operácie s adresármi. V mnohých ohľadoch je podobný adresáru. Niektoré z jeho vlastností a metód sú:
Create() : vytvorí adresár
CreateSubdirectory(path) : vytvorí podadresár na zadanej ceste
Delete() : vymaže adresár
Vlastnosť existuje: určuje, či adresár existuje
GetDirectories() : Získa zoznam adresárov
GetFiles() : získajte zoznam súborov
MoveTo(destDirName) : presunie adresár
Nadradená vlastnosť: získanie nadradeného adresára
Vlastnosť root: získanie koreňového adresára
Pozrime sa na príklady použitia týchto tried
Získanie zoznamu súborov a podadresárov
string dirName = "C:\\"; if (Directory.Exists(dirName)) ( Console.WriteLine("Subdirectories:"); string dirs = Directory.GetDirectories(dirName); foreach (reťazec s v adresári) ( Console.WriteLine(s); ) Console.WriteLine( ); Console.WriteLine("Files:"); string files = Directory.GetFiles(dirName); foreach (reťazce v súboroch) ( Console.WriteLine(s); ) )Všimnite si použitie lomiek v názvoch súborov. Buď použijeme dvojitú lomku: "C:\\" , alebo jednoduchú, ale potom dáme znak @ pred celú cestu: @"C:\Program Files"
Vytvorte adresár
string path = @"C:\SomeDir"; podcesta reťazca = @"program\avalon"; DirectoryInfo dirInfo = new DirectoryInfo (cesta); if (!dirInfo.Exists) ( dirInfo.Create(); ) dirInfo.CreateSubdirectory(podcesta);Najprv skontrolujeme, či taký adresár existuje, pretože ak existuje, nebude možné ho vytvoriť a aplikácia vyhodí chybu. V dôsledku toho dostaneme nasledujúcu cestu: "C:\SomeDir\program\avalon"
Získanie informácií o adresári
string dirName = "C:\\Program Files"; DirectoryInfo dirInfo = new DirectoryInfo(dirName); Console.WriteLine($"Názov adresára: (dirInfo.Name)"); Console.WriteLine($"Úplný názov adresára: (dirInfo.FullName)"); Console.WriteLine($"Čas vytvorenia adresára: (dirInfo.CreationTime)"); Console.WriteLine($"Root Directory: (dirInfo.Root)");Odstránenie adresára
Ak jednoducho aplikujeme metódu Delete na neprázdny priečinok, ktorý obsahuje nejaké súbory alebo podadresáre, potom aplikácia vyhodí chybu. Preto musíme do metódy Delete odovzdať ďalší parameter typu boolean, ktorý bude indikovať, že priečinok by sa mal odstrániť s celým obsahom:
String dirName = @"C:\SomeFolder"; try ( DirectoryInfo dirInfo = new DirectoryInfo(dirName); dirInfo.Delete(true); Console.WriteLine("Adresár odstránený"); ) catch (Exception ex) ( Console.WriteLine(ex.Message); )
String dirName = @"C:\SomeFolder"; Directory.Delete(dirName, true);
Presun adresára
string oldPath = @"C:\SomeFolder"; string newPath = @"C:\SomeDir"; DirectoryInfo dirInfo = new DirectoryInfo (stará cesta); if (dirInfo.Exists && Directory.Exists(newPath) == false) ( dirInfo.MoveTo(newPath); )Pri presúvaní musíme počítať s tým, že nový adresár, do ktorého chceme presunúť všetok obsah starého adresára, nesmie existovať.
Na uľahčenie manipulácie sa informácie v úložných zariadeniach ukladajú vo forme súborov.
Súbor je pomenovaná oblasť externej pamäte vyhradenej na ukladanie poľa údajov. Údaje obsiahnuté v súboroch sú najrozmanitejšieho charakteru: programy v algoritmickom alebo strojovom jazyku; počiatočné údaje pre prevádzku programov alebo výsledky vykonávania programu; ľubovoľné texty; grafika atď.
Adresár (priečinok, adresár) – pomenovaná kolekcia bajtov na pamäťovom médiu obsahujúca názvy podadresárov a súborov, používaná v súborovom systéme na zjednodušenie organizácie súborov.
systém súborov je funkčná časť operačného systému, ktorá zabezpečuje operácie so súbormi. Príkladmi súborových systémov sú FAT (FAT - File Allocation Table, filelocation table), NTFS, UDF (používané na CD).
Existujú tri hlavné verzie FAT: FAT12, FAT16 a FAT32. Líšia sa bitovosťou záznamov v štruktúre disku, t.j. počet bitov pridelených na uloženie čísla klastra. FAT12 sa používa hlavne pre diskety (do 4 KB), FAT16 pre malé disky, FAT32 pre veľkokapacitné FLASH mechaniky (do 32 GB).
Zvážte štruktúru súborového systému pomocou FAT32 ako príklad.
Štruktúra súborov FAT32
Externé pamäťové zariadenia v systéme FAT32 nemajú bajtové, ale blokové adresovanie. Informácie sa zapisujú na externé pamäťové zariadenie v blokoch alebo sektoroch.
Sektor – minimálna adresovateľná jednotka ukladania informácií na externých pamäťových zariadeniach. Veľkosť sektora je zvyčajne pevne stanovená na 512 bajtov. Na zväčšenie adresného priestoru externých pamäťových zariadení sa sektory spájajú do skupín nazývaných klastre.
Klaster je združenie viacerých sektorov, ktoré možno považovať za samostatnú jednotku s určitými vlastnosťami. Hlavnou vlastnosťou klastra je jeho veľkosť, meraná počtom sektorov alebo počtom bajtov.
Systém súborov FAT32 má nasledujúcu štruktúru.
Klastre používané na zapisovanie súborov sú číslované od 2. Klaster č. 2 sa spravidla používa v koreňovom adresári a počnúc od klastra č. 3 sa ukladá dátové pole. Sektory používané na ukladanie informácií nad koreňovým adresárom nie sú zoskupené.
Minimálna veľkosť súboru na disku je 1 klaster.
Zavádzací sektor začína nasledujúcimi informáciami:
- EB 58 90 - bezpodmienečná vetva a podpis;
- 4D 53 44 4F 53 35 2E 30 MSDOS5.0;
- 00 02 - počet bajtov v sektore (zvyčajne 512);
- 1 bajt - počet sektorov v klastri;
- 2 bajty - počet náhradných sektorov.
Okrem toho zavádzací sektor obsahuje nasledujúce dôležité informácie:
- 0x10 (1 byte) – počet tabuliek FAT (zvyčajne 2);
- 0x20 (4 bajty) - počet sektorov na disku;
- 0x2C (4 bajty) – číslo klastra koreňového adresára;
- 0x47 (11 bajtov) – označenie zväzku;
- 0x1FE (2 bajty) - Podpis zavádzacieho sektora (55 AA).
Informačný sektor súborového systému obsahuje:
- 0x00 (4 bajty) – podpis (52 52 61 41 );
- 0x1E4 (4 bajty) – podpis (72 72 41 61 );
- 0x1E8 (4 bajty) – počet voľných klastrov, -1, ak nie je známy;
- 0x1EC (4 bajty) – číslo posledného zaznamenaného klastra;
- 0x1FE (2 bajty) - podpis (55 AA).
Tabuľka FAT obsahuje informácie o stave každého klastra na disku. Spodné 2 bajty tabuľky FAT ukladajú F8 FF FF 0F FF FF FF FF (zodpovedá stavu klastrov 0 a 1, fyzicky chýbajú). Okrem toho stav každého klastra obsahuje číslo klastra, v ktorom aktuálny súbor pokračuje, alebo nasledujúce informácie:
- 00 00 00 00 – klaster je voľný;
- FF FF FF 0F je koniec aktuálneho súboru.
- 8 bajtov - názov súboru;
- 3 bajty - prípona súboru;
Koreňový adresár obsahuje množinu 32-bitových informačných záznamov pre každý súbor obsahujúci nasledujúce informácie:
Pri práci s dlhými názvami súborov (vrátane ruských názvov) je názov súboru zakódovaný v systéme kódovania UTF-16. V tomto prípade sú na kódovanie každého znaku pridelené 2 bajty. V tomto prípade je názov súboru napísaný vo forme nasledujúcej štruktúry:
- 1 bajtová sekvencia;
- 10 bajtov obsahuje spodných 5 znakov názvu súboru;
- 1 bajtový atribút;
- 1 bajt rezervovaný;
- 1 bajt - kontrolný súčet názvu DOS;
- 12 bajtov obsahuje spodné 3 znaky názvu súboru;
- 2 bajty – číslo prvého klastra;
- zvyšné znaky dlhého mena.
Práca so súbormi v C
Pre programátora je otvorený súbor reprezentovaný ako sekvencia dát, ktoré sa čítajú alebo zapisujú. Keď je súbor otvorený, je priradený k I/O tok. Výstupné informácie sa zapisujú do prúdu, vstupné informácie sa čítajú z prúdu.
Keď je prúd otvorený pre I/O, je spojený so štandardnou štruktúrou typu FILE, ktorá je definovaná v stdio.h. Štruktúra FILE obsahuje potrebné informácie o súbore.
Otvorenie súboru sa vykonáva pomocou funkcie fopen(), ktorá vracia ukazovateľ na štruktúru typu FILE , ktorú možno použiť na následné operácie so súborom.
SÚBOR *fopen(meno, typ);
name je názov súboru, ktorý sa má otvoriť (vrátane cesty),
typ je ukazovateľ na reťazec znakov, ktoré definujú spôsob prístupu k súboru:
- "r" - otvorený súbor na čítanie (súbor musí existovať);
- "w" - otvorte prázdny súbor na zápis; ak súbor existuje, jeho obsah sa stratí;
- "a" - otvorený súbor na zápis do konca (na pripojenie); súbor sa vytvorí, ak neexistuje;
- "r+" - otvorený súbor na čítanie a zápis (súbor musí existovať);
- "w+" - otvorenie prázdneho súboru na čítanie a zápis; ak súbor existuje, jeho obsah sa stratí;
- "a+" - otvorí súbor na čítanie a pridanie, ak súbor neexistuje, je vytvorený.
Návratová hodnota je ukazovateľ na otvorený stream. Ak sa nájde chyba, vráti sa NULL.
Funkcia fclose() zatvorí prúd alebo prúdy spojené so súbormi otvorenými pomocou fopen(). Prúd, ktorý sa má uzavrieť, je určený argumentom funkcie fclose().
Návratová hodnota: hodnota 0, ak bol prúd úspešne uzavretý; konštanta EOF, ak sa vyskytla chyba.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include
int main() (
SÚBOR *fp;
názov znaku = "my.txt" ;
if ((fp = fopen(meno, "r" )) == NULL )
{
printf( "Súbor sa nepodarilo otvoriť");
getchar();
návrat 0;
}
// otvorenie súboru bolo úspešné
... // požadované akcie s údajmi
fclose(fp);
getchar();
návrat 0;
}
Čítanie znaku zo súboru:
char fgetc(stream);
Argument funkcie je ukazovateľ na prúd typu FILE. Funkcia vráti kód načítaného znaku. Ak sa dosiahne koniec súboru alebo sa vyskytne chyba, vráti sa konštanta EOF.
Zápis znaku do súboru:
fputc(znak, stream);
Argumenty funkcie sú znak a ukazovateľ na prúd typu FILE . Funkcia vráti kód načítaného znaku.
Funkcie fscanf() a fprintf() sú podobné funkciám scanf() a printf(), ale pracujú s dátovými súbormi a ich prvým argumentom je ukazovateľ súboru.
fscanf(stream, "InputFormat" , args);