C'est quoi un fichier?

Jennifer -  
 le père -
Bonjour,


je débute en c et pour mieux le comprendre j'aimerais savoir ce qu'est un fichier, au niveau de la mémoire :
1. est-ce un emplacement contigu de bits, d'octets, de 32 bits?
2. Le fichier peut-il ne pas être contigu?
3. Si non, comment le lancer en mémoire vive, s'il fait plusieurs Mo? (il n'y a peut être pas autant de bits juxtaposés).
4. Et d'ailleurs, comment lancer des fichiers de plusieurs Go ?
5. Est-ce que l'extension a une importance dans la mémoire ?
6. Si c'est un fichier texte, on peut accéder au second caractère en lisant le 2eme octet?
7. Ces réponses sont-elles valables indépendamment de l'OS ?
8. Mêmes questions pour les dossiers.

Merci d'avance.
A voir également:

62 réponses

blux Messages postés 27121 Date d'inscription   Statut Modérateur Dernière intervention   3 359
 
Par contre, j'ignorais à ce niveau de précision l'existence d'un "gérant" de disque dur aussi sourcilleux et pour tout dire mal fait, je trouve.
Le "gérant" de disque dur n'est pas mal fait, il a ses faiblesses : entre un système mono-tâche et un système multitâches, les contraintes à gérer ne sont pas les mêmes...
Regarde windows, lorsque tu veux accéder à un fichier qui est déjà utilisé, il te jette en disant qu'il est ouvert dans un autre programme. C'est un moyen de s'affranchir des deadlocks, on rend le fichier mono-utilisateur, au lieu d'autoriser la modif des secteurs composant ce fichier de manière individuelle.

Les systèmes les plus modernes sont ils toujours entachés de cette possibilité fâcheuse de se bloquer à cause d'un deadlock ?
Tout ce qui bosse à l'aide de transactions : la plupart des mises à jours SQL et le temps réel (beaucoup plus sioux à gérer)...

Un peu plus ici (pour DB2) :
http://publib.boulder.ibm.com/infocenter/db2luw/v9r7/index.jsp?topic=/com.ibm.db2.luw.admin.perf.doc/doc/c0005266.html

Si une recherche de caractères dans une chaîne censée venant d'être écrite est lancée alors que l'écriture de la chaîne s'est interrompue, cela mène tout droit à des erreurs de mise en défaut de l'algorithme.
Non, puisque si l'écriture a été interrompue, on a fait un rollback : toutes les données écrites jusqu'à présent ont été remises à l'état initial, donc le process qui lit la chaîne la trouve intègre.
0
Jennifer
 
Merci pour ces réponses.
J'en reviens à mon idée de la dichotomie.
Existe-t-il une fonction qui amène au 1000eme caractère (ou ligne, ou octet, peu importe) sans avoir lu les 999 précédents, ou est-ce qu'une telle fonction ferait intérieurement la lecture des 999 précédents quand même?
D'une part c'est effectivement dans le cadre d'un travail scolaire, et d'autre part j'ai affaire à des fichiers de plusieurs Mo, donc une lecture totale serait assez longue.
0
du crétin, point te moquer tu ne dois
 
Hélas, trois fois hélas

Nous revenons à notre point de départ. Pour lire la nième ligne d'un fichier texte, il faut lire les n-1 précédentes.
Contrairement à un fichier de données classique organisé en enregistrements d'une longueur fixe, le fichier texte contient des chaines de caractères de taille variable. Comme on ne peut supposer une taille moyenne des chaines de caractères stockées dans un fichier texte (à moins de le lire en entier pour calculer cette moyenne !) on ne pourra jamais savoir dans quelle chaine se trouve un caractère pris au hasard.
0
du crétin, point te moquer tu ne dois
 
Pardon, ma réponse était un peu "orientée"
Oui, on peut lire le nième caractère d'un fichier, à condition de considérer ce fichier à accès direct (avec des enregistrements d'un caractère).
Avec les primitives des OS, on peut demander à se positionner un endroit en particulier et lire des caractères séquentiellement, voire faire passer ces caractères lus dans des fonctions de lecture/analyse de fichier texte pour présenter des lignes de texte comme si elles venaient d'un fichier texte... Mais tu n'auras jamais la certitude d'être sur la nième ligne d'un fichier texte
0
Jennifer
 
Donc concrètement en C on fait comment? (quelles sont les fonctions en question)
Je rappelle que mon but est d'accéder rapidement à une date d'un log sans avoir à lire toutes les lignes du fichier volumineux.
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
Jennifer
 
.
0
le père
 
fseek. voir messages 16 et 19 et le manuel des fonctions du C
0
heyquem Messages postés 759 Date d'inscription   Statut Membre Dernière intervention   131
 
Salut,

J'en reviens à mon idée de la dichotomie. 


Je vois que les regular expressions ne t’intéressent pas pour le moment. En fait, j’ai oublié de te citer une méthode, find, qui , combinée à une utilisation de regex, permet de trouver rapidement ce qu’on veut dans un texte.
On combine l’avantage des regex et de find() qui existe en tous cas en Python et ça m’étonnerait qu’elle n’existe pas en C. find() est très rapide.

Mais si tu tiens à mener une recherche par dichotomie,soit. Il va simplement te falloir utiliser d’autre outils et pour cela finir par t’intéresser comme un grande aux fonctions, en lisant leur docu.

Je ne connais que vaguement le C mais j’ai compris que fgets sert à lire. Donc elle ne suffit pas.


Existe-t-il une fonction qui amène au 1000eme caractère 
(ou ligne, ou octet, peu importe) sans avoir lu les 999 précédents, 
ou est-ce qu'une telle fonction ferait intérieurement la lecture des 
999 précédents quand même? 

Ben oui. On te l’a citée dans les messages 11, 16 et 19, et rappel en 31: seek.



Reste à savoir comment l’utiliser.
Si tu ne connais pas la taille a priori de ton fichier, à mon avis seek() n’est pas d’une grande utilité.
En Python, il y a une fonction qui permet de connaître cette taille: getsize(). Je pense qu’il y a la même en C, il faut chercher et lire sa docu.

Ce qui est important, c’est de se repréenter ce que fait telle ou telle fonction ou action.

Existe-t-il une fonction qui amène au 1000eme caractère 
(ou ligne, ou octet, peu importe)

Eh non, pas «peu importe».
Si tu fais aller à la 1000iéme ligne, le programme doit lire les octets et les tester.
Si tu fais aller au 1000ième octet, il compte les octets, il ne les teste pas.

getsize() renvoie la taille d’un fichier après avoir parcouru tout le fichier pour compter ses octets (ou alors la taille du fichier est elle inscrite dans une sorte d’en tête de fichier ?; ça c’est une question à laquelle blux sera capable de répondre); en tous cas l’important et l’intérèt d’une telle fonction, c’est que même si elle parcourt le fichier, elle le fait sans interpréter les octets, c’est à dire sans se demander si un octet est un ’r’ ou un ’6’ ou un ’\n’.

Cela représente une différence fondamentale avec une lecture ligne après ligne qui consiste nécessairement pour le programme à lire les octets les uns aprés les autres et à tester si chaque octet vaut ’\n’ pour savoir qu’il vient de lire une ligne complète. Donc il y a rapidité du processus avec find() par rapport a une lecture ligne par ligne.

Une fois que tu as la taille tu sais à quelle distance du début du fichier se trouve l’octet au milieu. Et il suffit de faire (c’est du code Python, qui se lit aussi bien que du pseudocode):
f = open(’ficier’,’r’)
taille = os.path.getsize(f)
if taille%2==0:
    f.seek(taille/2,0)
else:
    f.seek(taille/2 - 1,0)

Le 0 signifiant que le dé[placement (offset) se fait à partir du début du fichier (il y a certainement l’équivalent dans la fonction seek de C).
Et là , le pointeur de fichier est au milieu.

Ensuite tu peux faire lire toute la suite:
ch = f.read()

ou ne faire lire qu’un certain nombre de caractères:
ch = f.read(200)






Je rappelle que mon but est d'accéder rapidement
 à une date d'un log sans avoir à lire toutes les lignes du 
fichier volumineux.

Si tu veux que ce soit rapide , ce n’est pas la dichotomie qu’il faut utiliser, c’est la fonction find().
Siupposons que ta date soit tours précédée de quelque chose comme date_of_the_machin 23/04/2009
Tu fais chercher le début de ’date_of _the_machin ’:
pos = f.find(’date_of_the+machin’)

Et comme tu connais la longueur de ’date_of_the_machin ’, c’est à dire 19, tu déplaces le pointeur avec seek() jusqu’au début de la date, et tu la fais lire:
f.seek(pos+19, 1)
ch = f.read(10)



Et puis en cherchant sur internet, il y a plein de pages sur ce sujet. Tu penses bien que tu n’es pas la première à vouloir faire ce que tu cherches à faire. Par exemple, comme ca, tres rapidement
https://codes-sources.commentcamarche.net/
0
Jennifer
 
Merci pour les réponses.
Dans man fseek, je ne comprends pas bien le sens de cette phrase :
"A successful call to the fseek() function clears the end-of-file indicator for the stream and undoes any effects of the ungetc(3) and ungetwc(3) functions on the same stream."
Est-ce que vous pouvez m'aider à la comprendre?
Cela veut-il dire que l'on ne peut plus utiliser la fonction feof après avoir utilisé fseek? Quant à la seconde partie de la phrase, je ne comprends pas les "effects" dont il est question.
Merci.
0
heyquem Messages postés 759 Date d'inscription   Statut Membre Dernière intervention   131
 
Désolé, je ne sais pas.

Comme je crois que je l'ai dit dans un précédent post, C est un langage de bas-niveau dont l'intérêt et le désagrément (c'est selon l'objectif pour lequel on l'emploie) est de s'occuper de détails.

Je ne connais pas ce genre de détails parce que je ne pratique pas le C.

Il te faut attendre qu'une bonne âme compétente en C veuille bien s'intéresser à ta question.

Tu aurais intérêt, à mon idée, d'aller plutôt sur un forum dédié au langage C. Ici, tous les langages de programmation sont indifférenciés dans un seul forum.

Je vais voir si on me censure ce post.
0
Boulet moi aussi
 
Eh ! pourquoi de la censure ? t'es chez CCM quand même ;-)
0
heyquem Messages postés 759 Date d'inscription   Statut Membre Dernière intervention   131 > Boulet moi aussi
 
Parce que je lui conseille d'aller sur un autre site. Sans en citer un précisément, mais tout de même ailleurs.

J'ai lu des messages qui évoquaient des censures déjà.
0
blux Messages postés 27121 Date d'inscription   Statut Modérateur Dernière intervention   3 359 > heyquem Messages postés 759 Date d'inscription   Statut Membre Dernière intervention  
 
On vire le post quand ce n'est qu'une invitation à aller ailleurs, sans explication (ce qu'on appellerait pudiquement du 'racolage').

Pour ce cas précis, pas de problème... :-)
0
le père
 
La première partie de la phrase ne signifie absolument pas qu'on ne peut plus utiliser feof() ! Elle siginifie simplement que feof() devient faux (mais il redeviendra vrai quand la condition de fin de fichier sera de nouveau vérifiée).
La seconde partie de la phrase signifie que fseek annule les effets de ungetc et ungetwc. Quels effets ? Il suffit d'aller lire la doc de ces fonctions pour le savoir. ungetc 'remet' un caractère dans le flux, caractère qui serait normalement lu par un read suivant, mais qui est perdu si on utilise fseek entre temps.
0
Jennifer
 
Merci pour la réponse. Désolé, j'ai toujours un peu de mal à comprendre : feof() est une fonction qui renvoie 0 si la fin du fichier n'est pas atteinte, et 1 sinon, c'est bien ça? Ce que tu dis, c'est que feof() devient faux après l'appel de fseek, donc si on utilise fseek(fp,0,SEEK_END), qui nous amène à la fin, puis feof(fp), on reçoit 0 alors qu'on est à la fin?
ungetc recule d'un caractère, c'est bien ça? Et si on utilise dans un fichier f contenant "abc" fgetc(fp) puis ungetc(fp) puis fseek(fp,0,SEEK_CUR) puis fgetc(fp), alors au lieu de relire a, on lira b?
0
le père
 
Non, feof ne rend pas forcément 1 à la fin d'un fichier. feof rend une valeur différente de 0, qui t'a dit que c'était 1 ? Mais 'à la fin du fichier' signifie quand on a tenté de lire au-delà du dernier caractère. Tu n'as qu'à créer un fichier de 3 caractères et ne lire que les 3 caractères : feof() te rendra encore 0. Essaye de lire un autre caractère et teste à nouveau feof : tu auras une valeur différente de 0 (pas forcément 1 ).
Quand tu fais fseek(fp,0,SEEK_END), tu mets le curseur à la fin du fichier, mais tu n'essayes pas de lire au delà : feof() rend donc 0. Comme c'est dit dans la doc. As-tu fait un essai qui te laisse supposer que la doc ait tort ?

pour ta dernière question : ungetc ne recule pas d'un caractère. Où as-tu lu ça encore ? Donc ta dernière question n'a pas de sens.

Tu ne disposes pas d'un compilateur pour faire des essais et répondre aux questions que tu te poses ?
0
Jennifer
 
Le père, mes questions du message 37 essayaient simplement d'éclaircir tes propos du message 36...
Explique mieux cette phrase "Elle siginifie simplement que feof() devient faux" que j'ai comprise comme "feof() devient faux après l'appel de fseek, donc si on utilise fseek(fp,0,SEEK_END), qui nous amène à la fin, puis feof(fp), on reçoit 0 alors qu'on est à la fin".
Explique mieux cette phrase "Quels effets ? Il suffit d'aller lire la doc de ces fonctions pour le savoir. ungetc 'remet' un caractère dans le flux, caractère qui serait normalement lu par un read suivant, mais qui est perdu si on utilise fseek entre temps." que j'ai comprise comme "si on utilise dans un fichier f contenant "abc" fgetc(fp) puis ungetc(fp) puis fseek(fp,0,SEEK_CUR) puis fgetc(fp), alors au lieu de relire a, on lira b?"

En ce qui concerne ungetc, je m'exprime peut-être mal avec mon "recule d'un caractère", mais d'après ce que j'en ai compris, getc() lit un caractère d'un fichier et passe au caractère suivant, alors que ungetc() remet le caractère qui vient d'être lu dans le flux, ce qui correspond bien à reculer d'un caractère dans le fichier.
0
Jennifer
 
En attendant la réponse, une autre question : je crois voir comment récupérer la seconde ligne d'un fichier (on utilise getc tant qu'on n'a pas \n), mais comment récupérer la dernière, sans lire toutes les précédentes, puisqu'il s'agit d'un flux et qu'on ne peut donc utiliser un "getc qui partirait de la fin" ?
0
blux Messages postés 27121 Date d'inscription   Statut Modérateur Dernière intervention   3 359
 
Tu ne peux pas...

Un fichier est une suite de bits, le caractère de fin de ligne n'a une signification que pour toi. Un programme qui accède au fichier ne voit que des bytes.

Donc, à moins d'avoir des 'lignes' de taille fixe, tu ne peux envisager un positionnement direct à la n-ième ligne dans un fichier 'séquentiel'.
0
Jennifer
 
up
0
Jennifer
 
D'accord, je ne peux pas y accéder directement, mais je veux y accéder le plus rapidement possible.
Par exemple, si tous les caractères avaient été lus avec un fgetc, on aurait pu utiliser en partant de la fin unfgetc jusqu'a tomber sur \n, et on aurait alors notre dernière ligne. Mais cette methode est longue, n'y a-t-il pas une autre solution?
0
blux Messages postés 27121 Date d'inscription   Statut Modérateur Dernière intervention   3 359
 
Il y a d'autres solutions, mais peut-être pas en C...

- connaître la table d'implantation des secteurs disques concernant ce fichier
- lire le dernier secteur du fichier en accès direct
- rechercher dans ce dernier secteur les informations intéressantes (\n)

Ou alors faire une recherche google pour voir comment est programmée la commande unix 'tail' qui récupère les dernières lignes d'un fichier.
0
Jennifer
 
Que pensez-vous de faire une boucle while, récupérer un caractère, et si celui-ci est différent de '\n', alors faire fseek et déplacer le curseur de deux crans vers l'arrière (caractère lu + nouveau caractère), et continuer tant que l'on n'a pas trouvé deux '\n', le premier étant celui de la ligne où l'on est, le deuxième étant le '\n' juste avant la ligne que l'on souhaite récupérer ?

et peut-on répondre à mon post 42 ?
0
le père
 
D'abord je réponds à ton post 42. Je ne l'ai pas fait plus tôt parce qu'il m'arrive d'avoir autre chose à faire pendant la journée :-)

si on utilise fseek(fp,0,SEEK_END), qui nous amène à la fin, puis feof(fp), on reçoit 0 alors qu'on est à la fin"
Comme je l'ai dit dans le post 41, feof ne devient vrai que quand on essaye de lire au-delà de la fin. Pas quand on y est rendu.
En ce qui concerne le 'ungetc', ungetc() remet le caractère qui vient d'être lu : encore une fois : où as-tu lu ça ? On remet dans le flux le caractère qu'on veut. Pas obligatoirement celui qui vient d'être lu ! On peut donc difficilement parler de 'recul'

Pour ta recherche de la dernière ligne, ta méthode marche certainement. Mais tu aurais sans doute intérêt à faire un fread pour lire les caractères par paquets de taille donnée, disons 50, et utiliser les fonctions de recherche sur chaîne.
0
heyquem Messages postés 759 Date d'inscription   Statut Membre Dernière intervention   131
 
Salut

feof ne devient vrai que quand on essaye de lire au-delà de la fin. Pas quand on y est rendu.
Qu’est ce que ça veut dire «quand on y est rendu» ?



Est-ce qu’il existe une fonction en C qui permette de connaître la taille d’un fichier sans avoir à l’ouvrir , oui ou non ?

Python a cette fonction: getsize(fichier)
Et comme Python est implémenté en langage C, il doit bien y avoir une ou des fonctions C qui permettent de connaître cette donnée. Non ???

Car si on connaît la taille d’un fichier, on peut aller directement à son milieu avec fseek
Et on peut aussi aller par exemple 2000 caractères avant la fin et faire la lecture des lignes les unes après les autres, ce sera moins long que si on commençait par le début.


Mes propositions sont elles idiotes ?
0
le père
 
Bonjour

Pour avoir la taille d'un fichier en C :
fseek (pFile, 0, SEEK_END);
size=ftell (pFile);
0
heyquem Messages postés 759 Date d'inscription   Statut Membre Dernière intervention   131
 
Merci.

Quelqu’un a-t-il une idée de comment ftell fonctionne ?

Je suspecte que cette fonction part du début du fichier et qu’elle le parcourt en comptant les octets jusqu’à la position de mémoire indiquée par le pointeur pFile.

À moins que le “gestionnaire de mémoire“ comporte des données qui permettent à ftell de calculer la taille sans avoir à parcourir le fichier.
0
blux Messages postés 27121 Date d'inscription   Statut Modérateur Dernière intervention   3 359
 
Pas trop possible : si le fichier ne tient pas en mémoire ?

Ca rejoint un peu ce dont je parlais, il se pourrait que ftell sache quels sont les secteurs disques occupés par un fichier (via un appel à la table d'allocation des fichiers), aille lire le dernier secteur et recherche l'eof dans ce secteur, on aurait ainsi la taille du fichier : n secteurs de n bytes + quelques bytes pris dans le dernier secteur...

Ca me plairait comme explication :-)
0