Quel est le dernier caractère d'un fichier?

19

Je viens de lire les réponses à "Supprimer un caractère de nouvelle ligne à la fin d'un fichier" et tout le monde a dit de supprimer le dernier caractère. Ma question est, le caractère eof n'est-il pas le dernier?

Sworwitz
la source
11
EOF n'est pas un personnage .
Soren Bjornstad
1
@SorenBjornstad J'aimerais également ajouter que lorsqu'il y a une nouvelle ligne à la fin d'un fichier texte Unix, elle est là car elle termine la dernière ligne. Un fichier texte vide n'a pas de nouvelle ligne à la fin: c'est une séquence de zéro caractère.
Kaz
3
Pour être légèrement pédant, CPM et DOS ont utilisé ^ Z comme caractère EOF, et vous pouvez toujours parfois rencontrer des fichiers se terminant par ^ Z.
Edward Falk

Réponses:

13

Un fichier ne se termine pas par un caractère de fin de fichier, comme l'indiquent correctement les réponses précédentes. Mais je pense que les réponses et commentaires contiennent des inexactitudes qui méritent d'être signalées:

  • Le jeu de caractères ASCII ne contient pas de caractère EOF exact. Il existe plusieurs caractères de contrôle "fin": Fin du texte (3), Fin de la transmission (4), Fin du bloc de transmission (23), Fin du support (25). Le séparateur de fichiers (28) est peut-être le plus proche d'un caractère EOF. Le code 26 est "Substitute", pas EOF.

  • Ctrl- Dest uniquement associé à l'entrée du terminal. Par exemple, la commande cat filea fileb filec > outfilen'implique pas Ctrl- D. Soit dit en passant, vous pouvez remplacer le caractère EOF du terminal par autre chose que Ctrl- Dà l'aide de la sttycommande.

  • À strictement parler, Ctrl- D(ou ce que vous avez changé en) n'est pas un code clé EOF. Ce qu'il fait, c'est que l' readappel système retourne avec ce qui est disponible, tout comme appuyer sur retour fait que l'appel système lu renvoie une ligne de caractères à l'appelant. Par convention, une valeur de retour nulle de l'appel système lu (c'est-à-dire zéro caractère lu) signale une condition de fin de fichier. Cependant, le fichier d'entrée n'est pas fermé automatiquement et, si l'entrée provient du terminal, elle n'est pas mise dans un état "fin de fichier". Vous pouvez écrire un programme qui continue la lecture à partir du terminal même après une "fin de fichier" et l'appel lu peut retourner différent de zéro pour la ligne d'entrée suivante.

  • L'analogie entre les caractères eof et eol peut être vue si Ctrl- Dest enfoncé alors qu'une entrée a déjà été écrite sur la ligne. Par exemple, si vous écrivez "abc" et appuyez sur Ctrl- Dl'appel de lecture revient, cette fois avec une valeur de retour de 3 et avec "abc" stocké dans le tampon passé en argument. Étant donné que la lecture ne renvoie pas 0, cela n'est pas interprété comme une condition EOF par la convention ci-dessus. De même, en appuyant sur retour à, l'appel de lecture revient avec la ligne d'entrée entière (y compris la nouvelle ligne). Vous pouvez essayer cela avec la catcommande: écrivez quelques caractères sur la ligne et appuyez sur Ctrl- D. Vous verrez les personnages vous faire écho et catattendre plus de commentaires.

  • Tout ce qui précède ne s'applique que lorsque le terminal est en mode "cuit", par opposition au mode "brut", dans lequel le traitement d'entrée de ligne est minimisé. En mode brut, un caractère Ctrl-D est réellement envoyé au tampon d'entrée.

Johan Myréen
la source
19

Les caractères de contrôle ASCII ont des définitions des années 1960 (précédant en fait ce que vous pourriez considérer comme un réseau ). Tous ces caractères de contrôle ne sont pas utilisés comme ils étaient définis à l'époque pour les équipements de télécommunications.

Sur les systèmes de type Unix, il n'est pas nécessaire d'avoir un EOFpersonnage; aucun n'est utilisé. Le système peut indiquer aux applications combien d'octets se trouvent dans un fichier:

  • Sur certains autres systèmes (vu dans VMS, DOS, Windows), un contrôle-Z peut agir comme un marqueur de fin de fichier car dans les anciennes versions, le système ne pouvait pas dire à certaines applications combien d'octets se trouvaient dans le fichier.

    Dans le cas de VMS, la limitation était due à la façon dont le runtime C fonctionnait. Les applications en langage assembleur pouvaient (et ont obtenu) la bonne taille de fichier.

  • Les systèmes Unix dans le shell utilisent classiquement control-D pour indiquer à une application qu'une fin d'entrée (fichier) a été atteinte, mais le control-D n'est pas stocké dans le fichier.

En C, EOFest délibérément fait -1pour indiquer qu'il ne s'agit pas d'un caractère valide. Les E / S standard reviennent EOFlorsqu'une condition de fin de fichier est détectée - pas un caractère spécial.

Soit dit en passant, les fichiers ne doivent pas nécessairement se terminer par un caractère de nouvelle ligne (saut de ligne ASCII). Les éditeurs de texte peuvent gérer des fichiers qui sont tous du texte imprimable mais qui n'ont pas de nouvelle ligne de fin.

Thomas Dickey
la source
8
POSIX définit un fichier texte comme un fichier contenant une séquence de lignes et à son tour chaque ligne comme une séquence de caractères non-retour à la ligne suivie d'un retour à la ligne. Ainsi, un fichier se terminant par autre chose que 0x0A n'est pas un fichier texte conforme.
Damian Yerrick
2
J'en suis conscient, c'est pourquoi j'ai souligné que les éditeurs de texte fonctionnent. (Les fichiers binaires n'ont pas une telle contrainte).
Thomas Dickey
Il vaut vraiment la peine de noter que les fichiers destinés à être traités comme du texte qui n'ont pas de nouvelle ligne de fin sont toujours sans doute de mauvaise forme (même si les éditeurs de texte typiques ont été codés pour compenser ces fichiers), du moins si vous voulez réellement qu'il soit largement convivial / compatible, car l'absence d'une nouvelle ligne de fin peut ajouter des difficultés supplémentaires dans diverses circonstances (concaténation / impression de plusieurs fichiers texte, analyse avec des outils de ligne de commande typiques, éditeurs minimaux comme busyboxles vi, etc.).
mtraceur
(1) Avant VMS, RT-11 RSX-11 TOPS-10 avait des systèmes de fichiers uniquement précis pour un bloc et avait besoin d'un caractère EOF. Il en est de même de CP / M, qui l'a apparemment copié à partir de DEC et a été à son tour copié par les premiers MS-DOS, puis transmis à Windows. (2) Sous Unix, c'est le pilote tty et non le shell, comme décrit plus en détail par JohanM, bien que les gens exécutent généralement des shells sur des périphériques tty.
dave_thompson_085
Bien sûr - DEC était là-bas (et notez que j'ai mentionné des versions plus anciennes). Que ce soit l' origine de la fonction CP / M serait un sujet intéressant à explorer (pas ici); J'ai mentionné ces cas pour donner un aperçu des alternatives.
Thomas Dickey
7

EOF n'est pas un personnage. Il s'agit d'un état qui n'indique plus de caractères à lire dans un flux de fichiers. Lorsque vous entrez la commande EOF à partir du terminal, vous signalez au système d'exploitation de fermer le flux d'entrée, sans mettre de caractère spécial.

Munir
la source
1
Oui, mais dans le tableau ASCII EOF est 26, donc je pensais que le dernier octet était la représentation binaire de 26. Alors, comment un programme qui lit une entrée peut-il savoir où elle se termine?
sworwitz
ASCII était destiné à transmettre des informations sur un réseau. Dans ce cas, vous avez besoin d'un caractère EOF. (ASCII avait également beaucoup de codes de contrôle. Tout n'était pas imprimable.) Dans le cas de flux de fichiers, la taille du fichier est déjà connue via le système de fichiers afin que le système d'exploitation puisse savoir quand il n'y a plus de données à lire.
Munir
@sworwitz: En ce qui concerne C, les fonctions de lecture d'entrée qui renvoient un caractère par appel renvoient un int (généralement un nombre de 32 bits mais qui doit être au minimum de 16 bits) et non un caractère. La fonction signale et EOF en renvoyant -1 (0xffffffff) qui n'est pas une valeur de 8 bits valide, de sorte qu'elle ne sera confondue par aucun caractère ASCII, pas même 0xff. Les fonctions qui renvoient une chaîne retournent également la longueur des données lues. Cette longueur peut être utilisée pour signaler aucune donnée ou fin de données (encore une fois, la longueur peut être -1). Enfin, il y a aussi une fonction que vous pouvez appeler qui vous dira si un flux a atteint la fin
slebetman
D'accord, merci! Donc quand en bash j'appuie sur Ctrl + d je donne en entrée le caractère ASCII, non?
sworwitz
@sworwitz Pas exactement. Avant de mettre bashla main sur l'entrée, elle est massée par le pilote TTY. Ce pilote intercepte Ctrl-D et envoie un EOF à bash (Où EOF n'est pas un caractère, mais un statut de fichier spécial)
Stig Hemmer