Kürzlich habe ich das Buch „Computersysteme: Architektur und Programmierung. Das Aussehen des Programmierers. " Dort erwähnten die Autoren im Kapitel über das Unix-E / A-System, dass am Ende der Datei kein Sonderzeichen steht EOF
. Wenn Sie über das Unix / Linux-E / A-System gelesen oder damit experimentiert haben, wenn Sie C-Programme geschrieben haben, die Daten aus Dateien lesen, wird Ihnen diese Aussage wahrscheinlich völlig offensichtlich erscheinen. Aber schauen wir uns die folgenden zwei Aussagen genauer an, die sich auf das beziehen, was ich in dem Buch gefunden habe:
EOF
- Dies ist kein Symbol.- Am Ende der Dateien befindet sich kein Sonderzeichen.
Was ist das EOF
?EOF ist kein Symbol
Warum sagt oder denkt jemand, dass EOF
dies ein Symbol ist? Ich nehme an, dies kann so sein, weil Sie in einigen C-Programmen Code finden können, der explizite Überprüfungen für die EOF
Verwendung von Funktionen getchar()
und verwendet getc()
.Es könnte so aussehen: #include <stdio.h>
...
while ((c = getchar()) != EOF)
putchar(c);
Oder so: FILE *fp;
int c;
...
while ((c = getc(fp)) != EOF)
putc(c, stdout);
Wenn Sie sich die Hilfe für getchar()
oder ansehen getc()
, können Sie feststellen, dass beide Funktionen das nächste Zeichen aus dem Eingabestream lesen. Wahrscheinlich - genau das verursacht das Missverständnis über die Natur EOF
. Dies sind jedoch nur meine Annahmen. Kehren wir zu der Idee zurück, dass EOF
dies kein Symbol ist.Und was ist ein Symbol im Allgemeinen? Ein Symbol ist die kleinste Textkomponente. "A", "a", "B", "b" - all dies sind verschiedene Symbole. Ein Zeichen hat einen numerischen Code, der im Unicode-Standard als Codepunkt bezeichnet wird . Der lateinische Buchstabe „A“ hat beispielsweise einen Dezimalcode von 65. Dies kann schnell über die Befehlszeile des Python-Interpreters überprüft werden:$python
>>> ord('A')
65
>>> chr(65)
'A'
Oder schauen Sie sich die ASCII-Tabelle unter Unix / Linux an:$ man ascii
Wir werden herausfinden, welcher Code entspricht, EOF
indem wir ein kleines Programm in C schreiben. In ANSI C ist eine Konstante EOF
definiert stdio.h
, die Teil der Standardbibliothek ist. Normalerweise auf diese Konstante geschrieben -1
. Sie können den folgenden Code in einer Datei speichern printeof.c
, kompilieren und ausführen:#include <stdio.h>
int main(int argc, char *argv[])
{
printf("EOF value on my system: %d\n", EOF);
return 0;
}
Kompilieren Sie das Programm und führen Sie es aus:$ gcc -o printeof printeof.c
$ ./printeof
EOF value on my system: -1
Ich habe dieses Programm, getestet unter Mac OS und unter Ubuntu, berichtet, dass EOF
gleich -1
. Gibt es ein Zeichen mit diesem Code? Auch hier können Sie die Zeichencodes in der ASCII-Tabelle überprüfen, in der Unicode-Tabelle nachsehen, in welchem Bereich die Zeichencodes liegen können. Wir werden anders handeln: Wir werden den Python-Interpreter starten und die Standardfunktion verwenden chr()
, um uns das Symbol zu geben, das dem Code entspricht -1
:$ python
>>> chr(-1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: chr() arg not in range(0x110000)
Wie erwartet existiert das Zeichen mit dem Code -1
nicht. Also am Ende EOF
und die Wahrheit ist kein Symbol. Wir wenden uns nun der zweiten betrachteten Erklärung zu.Am Ende der Dateien befindet sich kein Sonderzeichen.
Vielleicht EOF
- das ist ein Sonderzeichen, das am Ende der Datei zu finden ist? Ich nehme an, Sie kennen die Antwort bereits. Aber lassen Sie uns unsere Annahme sorgfältig prüfen.Nehmen Sie eine einfache Textdatei, helloworld.txt , und zeigen Sie ihren Inhalt in hexadezimaler Darstellung an. Dazu können Sie den folgenden Befehl verwenden xxd
:$ cat helloworld.txt
Hello world!
$ xxd helloworld.txt
00000000: 4865 6c6c 6f20 776f 726c 6421 0a Hello world!.
Wie Sie sehen können, hat das letzte Zeichen der Datei einen Code 0a
. In der ASCII-Tabelle können Sie feststellen, dass dieser Code einem Zeichen entspricht nl
, dh einem Zeilenumbruchzeichen. Sie können dies mit Python herausfinden:$ python
>>> chr(0x0a)
'\n'
Damit. EOF
- Dies ist kein Symbol, und am Ende der Dateien befindet sich kein spezielles Symbol. Was ist das EOF
?Was ist ein EOF?
EOF
(Dateiende) ist ein Status, der von der Anwendung in einer Situation erkannt werden kann, in der der Dateilesevorgang sein Ende erreicht.Lassen Sie uns einen Blick darauf werfen, wie es möglich ist, den Status EOF
in verschiedenen Programmiersprachen beim Lesen einer Textdatei mithilfe der von diesen Sprachen bereitgestellten übergeordneten Eingabe- / Ausgabe-Tools zu erkennen. Dazu schreiben wir eine sehr einfache Version cat
, die aufgerufen wird mcat
. Es liest ASCII-Textbyte (Zeichen) und sucht explizit nach EOF
. Wir werden das Programm in den folgenden Sprachen schreiben:- ANSI C.
- Python 3
- Gehen
- JavaScript (Node.js)
Hier ist ein Repository mit Beispielcode. Wir fahren mit ihrer Analyse fort.ANSI C.
Beginnen wir mit dem ehrwürdigen C. Das hier vorgestellte Programm ist eine modifizierte Version cat
des Buches "C Programming Language".
#include <stdio.h>
int main(int argc, char *argv[])
{
FILE *fp;
int c;
if ((fp = fopen(*++argv, "r")) == NULL) {
printf("mcat: can't open %s\n", *argv);
return 1;
}
while ((c = getc(fp)) != EOF)
putc(c, stdout);
fclose(fp);
return 0;
}
Zusammenstellung:$ gcc -o mcat mcat.c
Starten:$ ./mcat helloworld.txt
Hello world!
Hier einige Erklärungen zum obigen Code:- Das Programm öffnet die übergebene Datei als Befehlszeilenargument.
- Die Schleife
while
kopiert Daten aus der Datei in den Standardausgabestream. Die Daten werden byteweise kopiert, dies geschieht bis das Ende der Datei erreicht ist. - Wenn das Programm erreicht
EOF
, schließt es die Datei und wird beendet.
Python 3
In Python gibt es keinen Mechanismus zum expliziten Suchen EOF
, ähnlich dem in ANSI C. Wenn Sie die Datei jedoch zeichenweise lesen, können Sie den Status EOF
anzeigen, wenn die Variable, in der das nächste gelesene Zeichen gespeichert ist, leer ist:# mcat.py
import sys
with open(sys.argv[1]) as fin:
while True:
c = fin.read(1) # 1
if c == '': # EOF
break
print(c, end='')
Führen Sie das Programm aus und sehen Sie sich die zurückgegebenen Ergebnisse an:$ python mcat.py helloworld.txt
Hello world!
Hier ist eine kürzere Version des gleichen Beispiels, das in Python 3.8+ geschrieben wurde. Hier wird der Operator verwendet : = (er wird als "Walross-Operator" oder "Walross-Operator" bezeichnet):# mcat38.py
import sys
with open(sys.argv[1]) as fin:
while (c := fin.read(1)) != '': # 1 EOF
print(c, end='')
Führen Sie diesen Code aus:$ python3.8 mcat38.py helloworld.txt
Hello world!
Gehen
In Go können Sie den von Read () zurückgegebenen Fehler explizit überprüfen, um festzustellen , ob das Ende der Datei erreicht ist:
package main
import (
"fmt"
"os"
"io"
)
func main() {
file, err := os.Open(os.Args[1])
if err != nil {
fmt.Fprintf(os.Stderr, "mcat: %v\n", err)
os.Exit(1)
}
buffer := make([]byte, 1)
for {
bytesread, err := file.Read(buffer)
if err == io.EOF {
break
}
fmt.Print(string(buffer[:bytesread]))
}
file.Close()
}
Führen Sie das Programm aus:$ go run mcat.go helloworld.txt
Hello world!
JavaScript (Node.js)
Node.js hat keinen Mechanismus zum expliziten Suchen nach EOF
. Wenn jedoch am Ende der Datei versucht wird, etwas anderes zu lesen, wird das End- Stream-Ereignis ausgelöst .
const fs = require('fs');
const process = require('process');
const fileName = process.argv[2];
var readable = fs.createReadStream(fileName, {
encoding: 'utf8',
fd: null,
});
readable.on('readable', function() {
var chunk;
while ((chunk = readable.read(1)) !== null) {
process.stdout.write(chunk);
}
});
readable.on('end', () => {
console.log('\nEOF: There will be no more data.');
});
Führen Sie das Programm aus:$ node mcat.js helloworld.txt
Hello world!
EOF: There will be no more data.
Low-Level-Systemmechanismen
Wie bestimmen die in den obigen Beispielen verwendeten übergeordneten E / A-Mechanismen das Ende der Datei? Unter Linux verwenden diese Mechanismen direkt oder indirekt den vom Kernel bereitgestellten Systemaufruf read () . Eine Funktion (oder ein Makro) getc()
aus C verwendet beispielsweise einen Systemaufruf read()
und gibt zurück, EOF
wenn read()
der Status angezeigt wird, in dem das Ende der Datei erreicht ist. In diesem Fall wird read()
zurückgegeben 0
. Wenn Sie dies alles in Form eines Diagramms darstellen, erhalten Sie Folgendes:Es stellt sich heraus, dass die Funktion auf getc()
basiert read()
.Wir werden eine Version mit dem cat
Namen schreiben, syscat
die nur Unix-Systemaufrufe verwendet. Wir werden dies nicht nur aus Interesse tun, sondern auch, weil es uns durchaus Vorteile bringen kann.Hier ist dieses Programm in C geschrieben:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
int fd;
char c;
fd = open(argv[1], O_RDONLY, 0);
while (read(fd, &c, 1) != 0)
write(STDOUT_FILENO, &c, 1);
return 0;
}
Starte es:$ gcc -o syscat syscat.c
$ ./syscat helloworld.txt
Hello world!
Dieser Code verwendet die Tatsache, dass die Funktion read()
, die angibt, dass das Ende der Datei erreicht ist, zurückgegeben wird 0
.Hier ist das gleiche Programm, das in Python 3 geschrieben wurde:# syscat.py
import sys
import os
fd = os.open(sys.argv[1], os.O_RDONLY)
while True:
c = os.read(fd, 1)
if not c: # EOF
break
os.write(sys.stdout.fileno(), c)
Starte es:$ python syscat.py helloworld.txt
Hello world!
Hier ist dasselbe, was in Python 3.8+ geschrieben wurde:# syscat38.py
import sys
import os
fd = os.open(sys.argv[1], os.O_RDONLY)
while c := os.read(fd, 1):
os.write(sys.stdout.fileno(), c)
Führen Sie auch diesen Code aus:$ python3.8 syscat38.py helloworld.txt
Hello world!
Zusammenfassung
EOF
- Dies ist kein Symbol.- Am Ende der Dateien befindet sich kein Sonderzeichen.
EOF
- Dies ist der vom Kernel gemeldete Status, der von der Anwendung erkannt werden kann, wenn der Datenlesevorgang das Ende der Datei erreicht.- In ANSI C
EOF
ist dies wiederum kein Zeichen. Dies ist die definierte Konstante, stdio.h
in die normalerweise der Wert -1 geschrieben wird. - Ein "Zeichen"
EOF
kann nicht in einer ASCII-Tabelle oder in Unicode gefunden werden.
Liebe Leser! Kennen Sie mehr oder weniger weit verbreitete Missverständnisse aus der Computerwelt?