Pouvez-vous me dire si c'est correct et si c'est portable s'il vous plait?
Merci d'avance.
Pouvez-vous me dire si c'est correct et si c'est portable s'il vous plait?
Merci d'avance.
Ceci n'est pas garanti par le standard C pour des fichiers texte:
Code C : Sélectionner tout - Visualiser dans une fenêtre à part fseek(fp,-2,SEEK_CUR);
Comment faire alors?
L'ouvrir en binaire? (ça change quelque chose??)
ok, merci beaucoup pour la réponse. C'est dur à trouver tout seul, votre aide est précieuse.
Il y a d'autres fautes dans ma fonction, à part ça?
et sinon, comment est-ce que je teste le système d'exploitation ?
Oui c'est dur, et c'est pourquoi je t'ai fait remarquer que si le fichier contient une marque facilement reconnaissable en début de ligne, tu peux ouvrir le fichier en mode binaire et rechercher le début de la ligne après chaque fseek. Quelle est la structure d'une ligne de ton fichier log ?
Un programme C est compilé donc le système d'exploitation ciblé tu le connais au moment même où tu compiles ... Si tu écris un programme portable, t'as aucune raison de connaître le système ciblé.sinon, comment est-ce que je teste le système d'exploitation ?
Mon fichier ne commence pas ces lignes par ; ni par # ou quelque autre caractère spécifique, il commence juste ses lignes par une date.
Pourriez-vous me donner un exemple où fseek ne marcherait pas bien pour un fichier texte, afin que je comprenne mieux?
Dommage alors. Dans ce cas la seule option qui te reste, si tu veux que le programme soit portable, c'est d'ouvrir le fichier en mode texte et le parcourir séquentiellement (ligne par ligne).Mon fichier ne commence pas ces lignes par ; ni par # ou quelque autre caractère spécifique, il commence juste ses lignes par une date.
Pourriez-vous me donner un exemple où fseek ne marcherait pas bien pour un fichier texte, afin que je comprenne mieux?Source : Manipulation des fichiers en C.(...) Un flux de texte est organisé en lignes. En langage C, une ligne est une suite de caractères terminée par le caractère de fin de ligne (inclus) : '\n'. Malheureusement, ce n'est pas forcément le cas pour le système sous-jacent. Sous Windows par exemple, la marque de fin de ligne est par défaut la combinaison de deux caractères : CR (Carriage Return) et LF (Line Feed) soit '\r' et '\n' (notez bien que c'est CR/LF c'est-à-dire CR suivi de LF pas LF suivi de CR). Sous UNIX, c'est tout simplement '\n'. On se demande alors comment on va pouvoir lire ou écrire dans un fichier, à travers un flux de texte, de manière portable. Et bien c'est beaucoup plus simple que ce à quoi vous-vous attendiez : lorsqu'on effectue une opération d'entrée/sortie sur un flux de texte, les données seront lues/écrites de façon à ce qu'elles correspondent à la manière dont elles doivent être représentées et non caractère pour caractère. C'est-à-dire par exemple que, dans une implémentation où la fin de ligne est provoquée par la combinaison des caractères CR et LF, l'écriture de '\n' sur un flux de texte va provoquer l'écriture effective des caractères '\r' et '\n' dans le fichier associé. Sur un flux binaire les données sont lues ou écrites dans le fichier caractère pour caractère.
(...) L'utilisation de fseek avec un flux de texte peut donner des résultats inattendus à cause du coup du '\n' ... Pour aller au n-ième caractère d'un fichier associé à un flux de texte (...), utilisez la méthode suivante : (...)
Sequentiellement, ça veut dire utiliser n fois getc au lieu de fseek(fp,n,seek_cur) c'est ça?
Je ne vois pas en quoi c'est plus portable...
C'est plus portable parce que fseek() ne peut pas gérer les retours à la ligne (et leur traduction de \r\n à \n seul, qui change leur taille) de manière fiable.
En mode binaire, tu supprimes la traduction, donc le changement de taille, donc fseek() redevient fiable.
Désolé j'ai toujours un peu de mal. Il me faudrait peut-être un exemple. Pourriez-vous m'en donner un s'il vous plait?
Prenons par exemple le fichier suivant (si vous avez un meilleur exemple, on peut prendre le votre) :
-Quel serait le 4eme caractère de ce fichier ouvert en mode binaire et en mode texte, sous windows et sous linux?
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 abc d
-Si on utilise 4 fois getc, qu'obtient-on en mode binaire et en mode texte, sous windows et sous linux?
-Si on utilise fseek(fp,4,seek_set) qu'obtient-on en mode binaire et en mode texte, sous windows et sous linux?
Je crois que les réponses à ces questions m'aideront à cerner le problème.
Sachez pour l'instant que je m'embrouille complètement et que je ne saurais répondre avec certitude à aucune de ces questions (bien que j'aie lu les liens donnés), donc votre aide sera très utile. Merci d'avance
'5e' serait plus parlant ici que 4e. Du moins, voici le contenu du fichier sous *n*x:
Et sous DOS/Windows:
Code X : Sélectionner tout - Visualiser dans une fenêtre à part 61 62 63 0A 64 0A
Code X : Sélectionner tout - Visualiser dans une fenêtre à part 61 62 63 0D 0A 64 0D 0A
Une lecture en mode texte avec juste des getc() est garantie donner ceci:
Et c'est à peu près tout ce qui est garanti.
Code C : Sélectionner tout - Visualiser dans une fenêtre à part {'a', 'b', 'c', '\n', 'd', '\n'};
En mode binaire, on aura le '\r' en plus sous Windows.
Pour le fseek(), c'est justement la partie non-garantie, et c'est là que le bât blesse; je n'ai pas testé et je n'ai pas le temps. C'est pourquoi on ne doit utiliser que des valeurs retournées par ftell().
D'ailleurs, c'est sans doute le résultat de ftell() qui sera le plus parlant: Si tu l'appelles après avoir fait quatre getc():
- sous *n*x, tu auras sans doute 4
- sous Windows, il est probable que tu aies 5 à la place (mais je n'ai pas testé).
Ok, je pense que j'ai compris, merci de ces explications.
Concrètement, quelles modifications dois-je donc apporter à mon programme pour qu'il devienne portable?
La solution serait-elle de l'ouvrir en binaire, et de créer une autre fonction (qui provoque un aller à la ligne sur un fichier tmp et vérifie si c'est \n ou \r\n) pour identifier le type de système, et créer une constante qui vaut soit \n soit \r\n ?
Ça dépend ce que tu cherches à faire.
Si tu cherches juste à remonter X lignes plus haut, tu peux rester en texte: il te suffit de mémoriser les valeurs retournées par ftell() pour les X dernières lignes...
Je ne cherche pas à remonter x lignes plus haut, je cherche à faire pointer fp sur le début de la ligne précédente. C'est le but de la fonction... (je n'ai pas vraiment compris la question en fait).
C'est simple alors:
- Début de la ligne courante: Un seul retour de ftell() à mémoriser, le dernier (en appellant ftell() après chaque getc() qui aurait retourné \n).
- Début de la ligne précédente: Deux retours de ftell() à mémoriser (les deux derniers).
Ce que vous êtes en train de dire, c'est qu'il faut lire le fichier en entier pour savoir quelle est l'emplacement de la ligne précédente?
Car c'est précisément ce que je veux éviter (cette fonction fait partie d'une fonction plus globale ayant pour but d'accéder à une date précise d'un log très long sans avoir à le parcourir en entier, en procédant par dichotomie)
non, a chaque nouvelle ligne, tu retiens le retour de ftell dans une file de un ou deux élément (pas bien compris là ou tu dois "revenir"). Quand tu aura trouvé ce que tu veux, tu sautes à la ligne voulu depuis le début du fichier.
"a chaque nouvelle ligne", ça veut dire qu'il faut parcourir le fichier en entier, non?
Vous avez un bloqueur de publicités installé.
Le Club Developpez.com n'affiche que des publicités IT, discrètes et non intrusives.
Afin que nous puissions continuer à vous fournir gratuitement du contenu de qualité, merci de nous soutenir en désactivant votre bloqueur de publicités sur Developpez.com.
Partager