Contacts

Travailler avec les données d'un fichier c. Travailler avec des fichiers texte. Lecture et écriture à partir d'un fichier binaire

Le travail des E/S de fichiers en C++ est presque le même que les E/S normales (mais avec quelques nuances).

Classes d'E/S de fichiers

il y a les trois principales classes d'E/S de fichiers en C++:

hors flux(est un enfant de la classe);

fstream(est un enfant de la classe iostream).

Vous pouvez utiliser ces classes pour effectuer une entrée de fichier unidirectionnelle, une sortie de fichier unidirectionnelle et des E/S de fichier bidirectionnelles. Pour les utiliser, il vous suffit de vous connecter à fstream.

Contrairement aux flux cout, cin, cerr et clog, qui peuvent être utilisés immédiatement, les flux de fichiers doivent être explicitement définis par le programmeur. C'est-à-dire que pour ouvrir un fichier en lecture et/ou en écriture, vous devez créer un objet de la classe d'E/S de fichier correspondante, en spécifiant le nom du fichier en paramètre. Ensuite, en utilisant les opérateurs d'insertion (<<) или извлечения (>>), vous pouvez écrire des données dans un fichier ou lire le contenu d'un fichier. Après cela, le final est - vous devez fermer le fichier : appelez explicitement méthode close () ou laissez simplement la variable d'E/S de fichier hors de portée (la classe d'E/S de fichier fermera automatiquement ce fichier pour nous).

Sortie de fichier

Pour écrire dans un fichier, utilisez classe de flux... Par example:

#inclure #inclure #inclure // pour utiliser exit () int main () (en utilisant l'espace de noms std ; // ofstream est utilisé pour écrire des données dans un fichier // Créer un fichier SomeText.txt ofstream outf ("SomeText.txt"); // Si nous ne pouvons pas ouvrez ce fichier pour y écrire des données if (! outf) (// Puis affichez un message d'erreur et exécutez 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 автоматически закроет наш файл }

#inclure

#inclure

#inclure // pour utiliser exit()

int main ()

en utilisant l'espace de noms std ;

// ofstream est utilisé pour écrire des données dans un fichier

// Créer un fichier SomeText.txt

ofstream outf ("SomeText.txt");

// Si nous ne pouvons pas ouvrir ce fichier pour y écrire des données

si (! outf)

// Ensuite, nous affichons un message d'erreur et exécutons exit()

cerr<< << endl ;

sortie (1) ;

// Écrivez les deux lignes suivantes dans le fichier

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

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

renvoie 0 ;

// Lorsque outf sort de la portée, le destructeur de la classe ofstream fermera automatiquement notre fichier

Si vous regardez dans votre répertoire de projet ( Faites un clic droit sur l'onglet avec le nom de votre fichier .cpp dans Visual Studio > "Ouvrir dossier contenant"), vous verrez un fichier nommé SomeText.txt contenant les lignes suivantes :

Voir ligne #1 !
Voir ligne #2 !

Veuillez noter que nous pouvons également utiliser méthode put() pour écrire un caractère dans un fichier.

Entrée de fichier

#inclure #inclure #inclure #inclure // pour utiliser exit () int main () (en utilisant l'espace de noms std ; // ifstream est utilisé pour lire le contenu du fichier // Essayez de lire le contenu du fichier SomeText.txt ifstream inf ("SomeText.txt") ; // Si on ne peut pas ouvrir ce fichier pour lire son contenu if (! 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; }

#inclure

#inclure

#inclure

#inclure // pour utiliser exit()

int main ()

en utilisant l'espace de noms std ;

// ifstream est utilisé pour lire le contenu du fichier

// Si on ne peut pas ouvrir ce fichier pour lire son contenu

si (! inf)

// Ensuite, nous affichons le message d'erreur suivant et exécutons exit ()

cerr<< << endl ;

sortie (1) ;

// Bien qu'il y ait des données que nous pouvons lire

tandis que (inf)

// Ensuite, nous déplaçons ces données dans une ligne, que nous affichons ensuite à l'écran

chaîne strInput;

inf >> strInput;

cout<< strInput << endl ;

renvoie 0 ;

// Quand inf sort de la portée, le destructeur de la classe ifstream fermera automatiquement notre fichier

Voir
ligne
#1!
Voir
ligne
#2!

Hum, ce n'est pas exactement ce que nous voulions. Comme nous le savons déjà dans les leçons précédentes, l'opérateur d'extraction travaille avec des "données formatées", c'est-à-dire. il ignore tous les espaces, tabulations et caractères de nouvelle ligne. Pour lire l'intégralité du contenu tel quel, sans le décomposer en parties (comme dans l'exemple ci-dessus), nous devons utiliser méthode getline():

#inclure #inclure #inclure #inclure // pour utiliser exit() int main() (en utilisant l'espace de noms std ; // ifstream est utilisé pour lire le contenu des fichiers // Nous allons essayer de lire le contenu du fichier SomeText.txt ifstream inf ("SomeText.txt "); // Si on ne peut pas ouvrir le fichier pour lire son contenu if (! inf) (// Alors afficher le message d'erreur suivant et exécuter 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 автоматически закроет наш файл }

#inclure

#inclure

#inclure

#inclure // pour utiliser exit()

int main ()

en utilisant l'espace de noms std ;

// ifstream est utilisé pour lire le contenu des fichiers

ifstream inf ("SomeText.txt");

// Si on ne peut pas ouvrir le fichier pour lire son contenu

si (! inf)

// Ensuite, nous affichons le message d'erreur suivant et exécutons exit ()

cerr<< "Euh oh, SomeText.txt n'a pas pu être ouvert pour la lecture !"<< endl ;

sortie (1) ;

tandis que (inf)

chaîne strInput;

getline (inf, strInput);

cout<< strInput << endl ;

renvoie 0 ;

// Quand inf sort de la portée, le destructeur de la classe ifstream fermera automatiquement notre fichier

Le résultat de l'exécution du programme ci-dessus :

Sortie tamponnée

La sortie C++ peut être mise en mémoire tampon. Cela signifie que tout ce qui est sorti dans le flux de fichiers ne peut pas être immédiatement écrit sur le disque (dans un fichier spécifique). Ceci est fait principalement pour des raisons de performance. Lorsque les données du tampon sont écrites sur le disque, elles sont appelées vidange du tampon... Une façon d'effacer le tampon est de fermer le fichier. Dans ce cas, tout le contenu du tampon sera déplacé sur le disque, puis le fichier sera fermé.

La mise en mémoire tampon de sortie n'est généralement pas un problème, mais dans certaines circonstances, elle peut causer des problèmes aux novices imprudents. Par exemple, lorsque des données sont stockées dans un tampon et que le programme termine son exécution prématurément (soit à la suite d'un échec, soit en appelant). Dans de tels cas, les destructeurs de classe d'E/S de fichiers ne sont pas exécutés, les fichiers ne sont jamais fermés, les tampons ne sont pas vidés et nos données sont perdues à jamais. C'est pourquoi c'est une bonne idée de fermer explicitement tous les fichiers ouverts avant d'appeler exit().

Le tampon peut également être effacé manuellement en utilisant ostream :: méthode flush() ou en envoyant std :: chasse d'eau au flux de sortie. N'importe laquelle de ces méthodes peut être utile pour garantir que le contenu du tampon est écrit sur le disque immédiatement en cas de plantage du programme.

Une nuance intéressante: Depuis std :: endl; efface également le flux de sortie, son utilisation excessive (conduisant à des vidages de tampon inutiles) peut affecter les performances du programme (puisque le vidage du tampon peut dans certains cas être une opération coûteuse). Pour cette raison, les programmeurs soucieux des performances de leur code utilisent souvent \ n au lieu de std :: endl pour insérer une nouvelle ligne dans le flux de sortie afin d'éviter un vidage inutile du tampon.

Modes d'ouverture de fichiers

Que se passe-t-il si nous essayons d'écrire des données dans un fichier existant ? Le redémarrage du programme ci-dessus (le tout premier) montre que le fichier d'origine est complètement écrasé lorsque le programme est redémarré. Que faire si nous devons ajouter des données à la fin du fichier ? Il s'avère que le flux de fichiers prend un deuxième paramètre facultatif, qui vous permet de dire au programmeur comment ouvrir le fichier. Comme ce paramètre, vous pouvez passer drapeaux suivants(qui sont dans la classe ios):

application- ouvre le fichier en mode ajout ;

a mangé- va à la fin du fichier avant lecture/écriture ;

binaire- ouvre le fichier en mode binaire (au lieu du mode texte) ;

dans- ouvre le fichier en lecture (par défaut pour ifstream) ;

en dehors- ouvre le fichier en mode enregistrement (par défaut pour ofstream) ;

tronc- supprime le fichier s'il existe déjà.

Vous pouvez spécifier plusieurs indicateurs à la fois en utilisant.

ifstream fonctionne sous ios :: en mode par défaut ;

ofstream fonctionne sous ios :: mode out par défaut;

fstream fonctionne par défaut en mode ios :: in OR ios :: out, ce qui signifie que vous pouvez à la fois lire le contenu d'un fichier et écrire des données dans un fichier.

Maintenant, écrivons un programme qui ajoute deux lignes au fichier SomeText.txt précédemment créé :

#inclure #inclure // pour utiliser exit() #include int main () (en utilisant l'espace de noms std; // Passez l'indicateur ios: app pour dire à fstream que nous allons ajouter nos données aux données du fichier existant, // nous n'allons pas écraser le fichier. Nous ne le faisons pas t besoin de passer l'ios :: out flag , // puisque ofstream fonctionne par défaut dans ios :: out ofstream outf mode ("SomeText.txt", ios :: app); // Si nous ne pouvons pas ouvrir le fichier pour écrire des données if (! outf) (// Ensuite, nous affichons le message d'erreur suivant et exécutons 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 автоматически закроет наш файл }

#inclure

#inclure // pour utiliser exit()

#inclure

int main ()

en utilisant l'espace de noms std ;

// Passez le drapeau ios: app pour dire à fstream que nous allons ajouter nos données aux données du fichier existant,

// nous n'allons pas écraser le fichier. Nous n'avons pas besoin de passer le drapeau ios :: out,

// puisque ofstream fonctionne sous ios :: mode out par défaut

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

// Si nous ne pouvons pas ouvrir le fichier pour écrire des données

si (! outf)

// Ensuite, nous affichons le message d'erreur suivant et exécutons exit ()

cerr<< "Euh oh, SomeText.txt n'a pas pu être ouvert pour l'écriture !"<< endl ;

sortie (1) ;

Les fichiers permettent à l'utilisateur de lire de grandes quantités de données directement à partir du disque sans les saisir à partir du clavier. Il existe deux principaux types de fichiers : texte et binaire.

Texte les fichiers composés de n'importe quel caractère sont appelés. Ils sont organisés en lignes dont chacune se termine par " fin de ligne "... La fin du fichier lui-même est indiquée par le symbole " fin de fichier "... Lors de l'écriture d'informations dans un fichier texte, qui peut être affiché à l'aide de n'importe quel éditeur de texte, toutes les données sont converties en un type de caractère et stockées sous forme de caractère.

DANS binaire fichiers, les informations sont lues et écrites sous forme de blocs d'une certaine taille, dans lesquels des données de toute nature et structure peuvent être stockées.

Pour travailler avec des fichiers, des types de données spéciaux sont utilisés, appelés ruisseaux. Couler ifstream sert à travailler avec des fichiers en mode lecture, et hors flux en mode enregistrement. Pour travailler avec des fichiers en mode écriture et lecture, utilisez le flux fstream.

Dans les programmes C ++, lorsque vous travaillez avec des fichiers texte, vous devez inclure des bibliothèques iostream et fstream.

Pour écrire des données dans un fichier texte, vous devez :

  1. décrire une variable de type hors flux.
  2. ouvert.
  3. des informations de sortie dans un fichier.
  4. assurez-vous de fermer le fichier.

Pour lire les données d'un fichier texte, vous devez :

  1. décrire une variable de type ifstream.
  2. ouvrir le fichier avec la fonction ouvert.
  3. lire les informations du fichier ; lors de la lecture de chaque donnée, il est nécessaire de vérifier si la fin du fichier est atteinte.
  4. fermez le fichier.

Ecrire des informations dans un fichier texte

Comme mentionné précédemment, pour commencer à travailler avec un fichier texte, vous devez déclarer une variable du type hors flux... Par exemple, comme ceci :

hors flux F;

Une variable sera créée F pour écrire des informations dans un fichier. L'étape suivante consiste à ouvrir le fichier pour l'écriture. En général, l'opérateur d'ouverture de flux ressemblera à ceci :

F.ouvert("Déposer", mode);

Ici F est une variable décrite comme hors flux, déposer- nom complet du fichier sur le disque, mode- mode de travail avec le fichier ouvert. Veuillez noter que vous devez utiliser une double barre oblique lorsque vous spécifiez le nom complet du fichier. Pour accéder, par exemple, à un fichier comptes.txt, situé dans le dossier des sites sur disque , le programme doit indiquer : D : \\ sites \\ comptes.SMS.

Le fichier peut être ouvert dans l'un des modes suivants :

  • ios :: dans- ouvrir le fichier en mode lecture de données ; mode est le mode par défaut pour les flux ifstream;
  • ios :: dehors- ouvrir le fichier en mode enregistrement des données (les informations sur le fichier existant sont détruites) ; mode est le mode par défaut pour les flux hors flux;
  • ios :: application- ouvrir le fichier en mode écriture de données à la fin du fichier ;
  • ios :: mangé- passer à la fin d'un fichier déjà ouvert ;
  • ios :: tronc- effacer le fichier, la même chose arrive en mode ios :: out;
  • ios :: nocreate- ne pas effectuer l'opération d'ouverture d'un fichier s'il n'existe pas ;
  • ios :: remplacer- ne pas ouvrir un fichier existant.

Le paramètre mode peut être absent, dans ce cas le fichier est ouvert dans le mode par défaut pour ce flux.

Après avoir ouvert avec succès le fichier (dans n'importe quel mode) dans la variable F sera gardé vrai, autrement faux... Cela vérifiera l'exactitude de l'opération d'ouverture du fichier.

Ouvrez un fichier (par exemple, prenez le fichier D : \\ sites \\ comptes.SMS) en mode enregistrement de l'une des manières suivantes :

Après avoir ouvert le fichier en mode écriture, un fichier vide sera créé, dans lequel vous pourrez écrire des informations.

Si vous souhaitez ouvrir un fichier existant en mode écrasement, utilisez la valeur ios :: application.

Après avoir ouvert un fichier en mode écriture, vous pouvez y écrire de la même manière que sur l'écran, uniquement à la place du périphérique de sortie standard cout vous devez spécifier le nom du fichier ouvert.

Par exemple, pour écrire dans le flux F variable une, l'opérateur de sortie sera :

F<

Pour une sortie séquentielle vers un flux g variables b, c, l'instruction de sortie devient :

g<

Le flux est fermé à l'aide de l'opérateur :

F.fermer ();

Considérez le problème suivant comme exemple.

Problème 1

Créer un fichier texte RÉ: \\ des sites\\comptes .SMS et écris-lui m nombres réels.

Décision

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"
#inclure
#inclure
#inclure
en utilisant l'espace de noms std ;
int main ()
{

entier je, n;
Double A;
// décrit un flux pour écrire des données dans un fichier
hors flux f;
// ouvre le fichier en écriture,
// ios :: le mode de sortie est défini par défaut
f.open ("D : \\ sites \\ comptes.txt ", ios :: out);
// entrer le nombre de nombres réels
cout<< «n=» ; cin >> n;
// boucle pour saisir des nombres réels
// et les écrire dans un fichier
pour (i = 0; je< n; i++ )
{
cout<< «a=» ;
// entrer un nombre
cin >> a;
F<< a<< «\ t ";
}
// ferme le flux
f.fermer ();
système ("pause");
renvoie 0 ;
}

Lire des informations à partir d'un fichier texte

Pour lire les informations d'un fichier texte, vous devez déclarer une variable du type ifstream... Après cela, vous devez ouvrir le fichier en lecture à l'aide de l'opérateur ouvert... Si la variable est appelée F, alors les deux premiers opérateurs seront comme ceci :

Après avoir ouvert un fichier en lecture, vous pouvez en lire les informations de la même manière qu'à partir du clavier, uniquement au lieu de cintre vous devez spécifier le nom du flux à partir duquel les données seront lues.

Par exemple, pour lire les données d'un flux F dans une variable une, l'instruction d'entrée ressemblera à ceci :

F >> a;

Deux nombres dans un éditeur de texte sont considérés comme séparés s'il y a au moins un des caractères entre eux : espace, tabulation, caractère de fin de ligne. C'est bien quand le programmeur sait à l'avance combien et quelles valeurs sont stockées dans un fichier texte. Cependant, souvent, seul le type de valeurs stockées dans le fichier est connu et leur nombre peut varier. Pour résoudre ce problème, il faut lire les valeurs du fichier une par une, et avant chaque lecture, vérifier si la fin du fichier est atteinte. Et la fonction aidera à le faire F.eof ()... Ici F- le nom du flux, la fonction retourne une valeur booléenne : vrai ou alors faux, selon que la fin du fichier est atteinte ou non.

Par conséquent, la boucle de lecture du contenu du fichier entier peut être écrite comme ceci :

Pour une meilleure assimilation de la matière, considérez le problème.

Problème 2

Le fichier texte D: \\ game \\ account.txt stocke des nombres réels, les affiche à l'écran et calcule leur nombre.

Décision

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"
#inclure
#inclure
#inclure
#inclure
en utilisant l'espace de noms std ;
int main ()
{
setlocale (LC_ALL, "RUS");
entier n = 0;
flotteur a;
fstream F;
// ouvre le fichier en lecture
F.ouvert ("D : \\ sites \\ comptes.txt ") ;
// si le fichier a été ouvert correctement, alors
si (F)
{
// boucle pour lire les valeurs d'un fichier ; l'exécution du cycle sera interrompue,
// lorsque nous atteignons la fin du fichier, dans ce cas F.eof() retournera true.
tandis que (! F.eof ())
{
// lit la valeur suivante du flux F dans la variable a
F >> a;
// affiche la valeur de la variable a à l'écran
cout<< a<< «\ t ";
// augmente le nombre de nombres lus
n++;
}
// ferme le flux
F.fermer ();
// entrée à l'écran le nombre de nombres lus
cout<< «n=» << n<< endl;
}
// si le fichier n'a pas été ouvert correctement, alors la sortie
// messages sur l'absence d'un tel fichier
autrement cout<< " Le fichier n'existe pas"<< endl;
système ("pause");
renvoie 0 ;
}

Ceci conclut la leçon relativement volumineuse sur les fichiers texte. Le prochain article examinera les techniques de manipulation par lesquelles le C++ gère.

Dernière mise à jour : 31.10.2015

Il existe deux classes pour travailler avec des répertoires dans l'espace de noms System.IO : Directory et DirectoryInfo.

Classe d'annuaire

La classe Directory fournit un certain nombre de méthodes statiques pour la gestion des répertoires. Certaines de ces méthodes sont :

    CreateDirectory (path) : crée un répertoire au chemin spécifié

    Supprimer (chemin): supprime le répertoire au chemin spécifié

    Existe (chemin) : détermine si un répertoire existe au chemin spécifié. S'il existe, il renvoie vrai, s'il n'existe pas, alors faux

    GetDirectories (path) : obtient une liste des répertoires dans le répertoire path

    GetFiles (chemin) : obtient une liste des fichiers dans le répertoire du chemin

    Déplacer (sourceDirName, destDirName): déplace le répertoire

    GetParent (chemin) : obtenir le répertoire parent

Classe DirectoryInfo

Cette classe fournit des fonctionnalités pour la création, la suppression, le déplacement et d'autres opérations avec des répertoires. À bien des égards, il est similaire à Directory. Certaines de ses propriétés et méthodes :

    Créer () : crée un répertoire

    CreateSubdirectory (path) : crée un sous-répertoire au chemin spécifié

    Supprimer () : supprime un répertoire

    Propriété Exists : détermine si le répertoire existe

    GetDirectories (): obtient une liste de répertoires

    GetFiles (): obtient une liste de fichiers

    MoveTo (destDirName) : déplace un répertoire

    Propriété parent : obtenir le répertoire parent

    Propriété racine : obtenir le répertoire racine

Regardons des exemples d'utilisation de ces classes.

Obtenir une liste de fichiers et de sous-répertoires

string dirName = "C: \\"; if (Directory.Exists (dirName)) (Console.WriteLine ("Sous-répertoires :"); string dirs = Directory.GetDirectories (dirName); foreach (string s in dirs) (Console.WriteLine (s);) Console.WriteLine ( ); Console.WriteLine ("Files:"); string files = Directory.GetFiles (dirName); foreach (string s in files) (Console.WriteLine (s);))

Notez l'utilisation de barres obliques dans les noms de fichiers. Soit on utilise un double slash : "C: \\", soit un simple slash, mais ensuite on met le signe @ devant tout le chemin : @ "C: \ Program Files"

Création d'un répertoire

chemin de chaîne = @ "C: \ SomeDir"; string subpath = @ "programme \ avalon"; DirectoryInfo dirInfo = new DirectoryInfo (chemin) ; if (! dirInfo.Exists) (dirInfo.Create ();) dirInfo.CreateSubdirectory (sous-chemin);

Tout d'abord, nous vérifions s'il existe un tel répertoire, car s'il existe, il ne sera pas possible de le créer et l'application générera une erreur. En conséquence, nous obtenons le chemin suivant : "C: \ SomeDir \ program \ avalon"

Récupération des informations du répertoire

string dirName = "C: \\ Program Files"; DirectoryInfo dirInfo = new DirectoryInfo (dirName); Console.WriteLine ($ "Nom du répertoire : (dirInfo.Name)"); Console.WriteLine ($ "Nom complet du répertoire : (dirInfo.FullName)"); Console.WriteLine ($ "Heure de création du répertoire : (dirInfo.CreationTime)"); Console.WriteLine ($ "Répertoire racine : (dirInfo.Root)");

Supprimer un répertoire

Si nous appliquons simplement la méthode Delete à un dossier non vide contenant des fichiers ou des sous-répertoires, l'application nous renverra une erreur. Par conséquent, nous devons passer un paramètre booléen supplémentaire à la méthode Delete, qui indiquera que le dossier doit être supprimé avec tout son contenu :

String dirName = @ "C: \ SomeFolder"; try (DirectoryInfo dirInfo = new DirectoryInfo (dirName); dirInfo.Delete (true); Console.WriteLine ("Répertoire supprimé");) catch (Exception ex) (Console.WriteLine (ex.Message);)

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

Déplacer un répertoire

string oldPath = @ "C: \ SomeFolder"; string newPath = @ "C: \ SomeDir"; DirectoryInfo dirInfo = new DirectoryInfo (oldPath); if (dirInfo.Exists && Directory.Exists (newPath) == false) (dirInfo.MoveTo (newPath);)

Lors du déplacement, il convient de garder à l'esprit que le nouveau répertoire, dans lequel nous voulons déplacer tout le contenu de l'ancien répertoire, ne doit pas exister.

Pour plus de commodité, les informations contenues dans les périphériques de stockage sont stockées sous forme de fichiers.

Le fichier est une zone nommée de mémoire externe allouée pour stocker un tableau de données. Les données contenues dans les fichiers sont de la nature la plus variée : programmes en langage algorithmique ou machine ; les données initiales pour le fonctionnement des programmes ou les résultats de l'exécution des programmes ; textes arbitraires; graphiques, etc

Répertoire (dossier, répertoire) - une collection nommée d'octets sur un support de stockage, contenant le nom des sous-répertoires et des fichiers, est utilisée dans le système de fichiers pour simplifier l'organisation des fichiers.

Système de fichiers est la partie fonctionnelle du système d'exploitation qui fournit des opérations sur les fichiers. Des exemples de systèmes de fichiers sont FAT (FAT - File Allocation Table), NTFS, UDF (utilisé sur les CD).

Il existe trois versions principales de FAT : FAT12, FAT16 et FAT32. Ils diffèrent par le nombre de bits des enregistrements dans la structure du disque, c'est-à-dire le nombre de bits alloués pour stocker le numéro de cluster. FAT12 est principalement utilisé pour les disquettes (jusqu'à 4 Ko), FAT16 pour les petits disques, FAT32 pour les lecteurs FLASH de grande capacité (jusqu'à 32 Go).

Regardons la structure du système de fichiers en utilisant FAT32 comme exemple.

Structure de fichier FAT32

Les dispositifs de mémoire externes dans le système FAT32 n'ont pas d'adressage d'octet, mais d'adressage de bloc. Les informations sont écrites sur le périphérique de mémoire externe par blocs ou secteurs.

Un secteur est la plus petite unité adressable de stockage d'informations sur des périphériques de stockage externes. Typiquement, la taille du secteur est fixée à 512 octets. Pour augmenter l'espace d'adressage des périphériques de mémoire externes, les secteurs sont combinés en groupes appelés clusters.

Un cluster est une union de plusieurs secteurs, qui peuvent être considérés comme une unité indépendante avec certaines propriétés. La principale propriété d'un cluster est sa taille, mesurée en nombre de secteurs ou en nombre d'octets.

Le système de fichiers FAT32 a la structure suivante.

Les clusters utilisés pour l'enregistrement des fichiers sont numérotés à partir de 2. En règle générale, le cluster #2 est utilisé par le répertoire racine, et à partir du cluster #3, un tableau de données est stocké. Les secteurs utilisés pour stocker les informations présentées au-dessus du répertoire racine ne sont pas regroupés.
La taille minimale du fichier sur le disque est de 1 cluster.

Le secteur de démarrage commence par les informations suivantes :

  • EB 58 90 - branche et signature inconditionnelles ;
  • 4D 53 44 4F 53 35 2E 30 MSDOS5.0 ;
  • 00 02 - le nombre d'octets dans le secteur (généralement 512);
  • 1 octet - le nombre de secteurs dans le cluster ;
  • 2 octets - le nombre de secteurs de réserve.

De plus, le secteur de démarrage contient les informations importantes suivantes :

  • 0x10 (1 octet) - nombre de tables FAT (généralement 2);
  • 0x20 (4 octets) - le nombre de secteurs sur le disque ;
  • 0x2С (4 octets) - numéro de cluster du répertoire racine ;
  • 0x47 (11 octets) - étiquette de volume ;
  • 0x1FE (2 octets) - signature du secteur de démarrage (55 AA).

Le secteur d'informations du système de fichiers contient :

  • 0x00 (4 octets) - signature (52 52 61 41);
  • 0x1E4 (4 octets) - signature (72 72 41 61);
  • 0x1E8 (4 octets) - nombre de clusters libres, -1 si inconnu ;
  • 0x1EC (4 octets) - numéro du dernier cluster enregistré ;
  • 0x1FE (2 octets) - signature (55 AA).

Le FAT contient des informations sur l'état de chaque cluster sur le disque. Les 2 octets inférieurs du FAT stockent F8 FF FF 0F FF FF FF FF (ce qui correspond à l'état des clusters 0 et 1, qui sont physiquement absents). De plus, l'état de chaque cluster contient le numéro du cluster dans lequel le fichier actuel continue ou les informations suivantes :

  • 00 00 00 00 - le cluster est libre ;
  • FF FF FF 0F - fin du fichier courant.
  • 8 octets - nom de fichier ;
  • 3 octets - extension de fichier ;

Le répertoire racine contient un ensemble d'enregistrements d'informations 32 bits pour chaque fichier, contenant les informations suivantes :

Lorsque vous travaillez avec des noms de fichiers longs (y compris des noms russes), le nom de fichier est codé dans le système de codage UTF-16. Dans ce cas, 2 octets sont alloués pour encoder chaque caractère. Dans ce cas, le nom du fichier est écrit sous la forme de la structure suivante :

  • 1 octet de séquence ;
  • 10 octets contiennent les 5 caractères les moins significatifs du nom de fichier ;
  • attribut 1 octet ;
  • 1 octet réservé ;
  • 1 octet - somme de contrôle du nom DOS ;
  • 12 octets contiennent les 3 caractères les moins significatifs du nom de fichier ;
  • 2 octets - numéro du premier cluster ;
  • autres caractères du nom long.

Travailler avec des fichiers en langage C

Pour le programmeur, un fichier ouvert est représenté comme une séquence de données en cours de lecture ou d'écriture. Lorsque le fichier est ouvert, il est associé à Flux d'E/S... Les informations de sortie sont écrites dans le flux, les informations d'entrée sont lues à partir du flux.

Lorsqu'un flux est ouvert pour les E/S, il s'associe à une structure standard de type FILE, qui est définie dans stdio.h. La structure FILE contient les informations nécessaires sur le fichier.

Le fichier est ouvert à l'aide de la fonction fopen (), qui renvoie un pointeur vers une structure FILE, qui peut être utilisée pour des opérations ultérieures sur le fichier.

FICHIER * fopen (nom, type);


name - le nom du fichier à ouvrir (y compris le chemin),
type est un pointeur vers une chaîne de caractères qui détermine comment accéder au fichier :
  • "r" - ouvre un fichier en lecture (le fichier doit exister);
  • "w" - ouvre un fichier vide pour l'écriture ; si le fichier existe, alors son contenu est perdu ;
  • "a" - ouvre le fichier pour l'écriture jusqu'à la fin (pour l'ajout); le fichier est créé s'il n'existe pas ;
  • "r +" - ouvre un fichier en lecture et en écriture (le fichier doit exister);
  • "w +" - ouvre un fichier vide pour la lecture et l'écriture ; si le fichier existe, alors son contenu est perdu ;
  • "a +" - ouvre le fichier pour lecture et ajout, si le fichier n'existe pas, alors il est créé.

La valeur de retour est un pointeur vers le flux ouvert. Si une erreur est rencontrée, NULL est renvoyé.

La fonction fclose() ferme le ou les flux associés aux fichiers ouverts avec fopen(). Le flux à fermer est déterminé par l'argument de la fonction fclose().

Valeur renvoyée : valeur 0 si le flux a été fermé avec succès ; EOF constant si une erreur s'est produite.

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

#inclure
int main () (
FICHIER * fp;
nom de caractère = "mon.txt" ;
if ((fp = fopen (nom, "r")) == NULL)
{
printf ( "Impossible d'ouvrir le fichier");
getchar ();
renvoie 0 ;
}
// réussi à ouvrir le fichier
... // actions requises sur les données
ffermer (fp);
getchar ();
renvoie 0 ;
}

Lire un caractère dans un fichier:

char fgetc (flux);


L'argument de fonction est un pointeur vers un flux de type FICHIER. La fonction renvoie le code du caractère lu. Si la fin du fichier est atteinte ou si une erreur se produit, la constante EOF est renvoyée.

Ecrire un caractère dans un fichier:

fputc (caractère, flux);

Les arguments de la fonction sont un caractère et un pointeur vers un flux de type FICHIER. La fonction renvoie le code du caractère lu.

Les fonctions fscanf () et fprintf () sont similaires aux fonctions scanf () et printf (), mais elles fonctionnent avec des fichiers de données et ont un pointeur de fichier comme premier argument.

fscanf (flux, "Format d'entrée", arguments);



Vous avez aimé l'article ? Partagez-le