Jaki jest ostatni znak w pliku?

19

Właśnie przeczytałem odpowiedzi na „Usuwanie znaku nowej linii na końcu pliku” i wszyscy mówili, aby usunąć ostatni znak. Moje pytanie brzmi: czy eof nie jest ostatnim?

sworwitz
źródło
11
EOF nie jest postacią .
Soren Bjornstad,
1
@ SorenBjornstad Chciałbym również dodać, że gdy na końcu pliku tekstowego uniksowego znajduje się nowa linia, to tam, ponieważ kończy ostatnią linię. Pusty plik tekstowy nie ma na końcu nowego wiersza: jest to ciąg zerowych znaków.
Kaz
3
Aby być nieco pedantycznym, CPM i DOS użyły ^ Z jako znaku EOF, a czasami możesz napotkać pliki, które kończą się na ^ Z.
Edward Falk,

Odpowiedzi:

13

Plik nie kończy się znakiem końca pliku, ponieważ poprzednie odpowiedzi są prawidłowe. Myślę jednak, że odpowiedzi i komentarze zawierają pewne nieścisłości, na które warto zwrócić uwagę:

  • Zestaw znaków ASCII nie zawiera dokładnego znaku EOF. Istnieje kilka znaków kontrolnych „koniec”: Koniec tekstu (3), Koniec transmisji (4), Koniec bloku transmisji (23), Koniec medium (25). Separator plików (28) może być najbliżej znaku EOF. Kod 26 to „Zastępczy”, a nie EOF.

  • Ctrl- Djest powiązany tylko z wejściem terminalowym. Na przykład polecenie cat filea fileb filec > outfilenie obejmuje Ctrl- D. Nawiasem mówiąc, możesz zmienić znak terminala EOF na coś innego niż Ctrl- Dza pomocą sttypolecenia.

  • Ściśle mówiąc Ctrl- D(lub cokolwiek, na co się zmieniłeś) nie jest kodem klucza EOF. Co robi to zrobić readsystem zwrotu rozmowę z tym, co jest wejście dostępne, podobnie jak naciśnięcie powrotu sprawia, że wywołanie systemowe read zwróci linię znaków do rozmówcy. Zgodnie z konwencją zwracana wartość zero z odczytanego wywołania systemowego (tj. Odczyt zerowych znaków) sygnalizuje koniec stanu pliku. Plik wejściowy nie jest jednak automatycznie zamykany, a jeśli dane wejściowe pochodzą z terminala, nie są wprowadzane w stan „końca pliku”. Możesz napisać program, który kontynuuje czytanie z terminala nawet po „końcu pliku”, a wywołanie odczytu może zwrócić wartość niezerową dla następnego wiersza wejściowego.

  • Analogię między znakami eof i eol można zobaczyć, jeśli Ctrl- Dzostanie naciśnięty, gdy jakieś wejście zostało już zapisane w wierszu. Na przykład, jeśli napiszesz „abc” i naciśniesz Ctrl- Dwywołanie read powraca, tym razem z wartością zwracaną 3 i „abc” zapisanym w buforze przekazywanym jako argument. Ponieważ odczyt nie zwraca 0, nie jest to interpretowane jako warunek EOF zgodnie z powyższą konwencją. Podobnie, naciśnięcie klawisza Return powoduje zwrócenie odczytanego połączenia z całą linią wprowadzania (w tym nową linią). Możesz to wypróbować za pomocą catpolecenia: wpisz kilka znaków w wierszu i naciśnij Ctrl- D. Zobaczysz echa z powrotem do ciebie i catczeka na więcej informacji.

  • Wszystkie powyższe mają zastosowanie tylko wtedy, gdy terminal jest w trybie „gotowym”, w przeciwieństwie do trybu „surowego”, w którym przetwarzanie wejścia liniowego jest zminimalizowane. W trybie raw znak Ctrl-D naprawdę jest dostarczany do bufora wejściowego.

Johan Myréen
źródło
19

Znaki kontrolne ASCII mają definicje z lat 60. XX wieku (faktycznie poprzedzające to, co można uznać za sieć ). Nie wszystkie z tych znaków kontrolnych są używane w sposób, w jaki były wówczas definiowane dla sprzętu telekomunikacyjnego.

W systemach uniksowych EOFznak nie jest potrzebny ; żaden nie jest używany. System może powiedzieć aplikacjom, ile bajtów znajduje się w pliku:

  • W niektórych innych systemach (widoczne w VMS, DOS, Windows), control-Z może działać jako znacznik końca pliku, ponieważ w starszych wersjach system nie mógł powiedzieć niektórym aplikacjom, ile bajtów jest w pliku.

    W przypadku VMS ograniczenie było spowodowane sposobem działania środowiska wykonawczego C. Aplikacje w asemblerze mogły (i zrobiły) uzyskać prawidłowy rozmiar pliku.

  • Systemy uniksowe w powłoce konwencjonalnie używają control-D, aby powiedzieć aplikacji, że osiągnięto koniec wejścia (pliku), ale control-D nie jest zapisany w pliku.

W C EOFjest celowo wykonany, -1aby wskazać, że nie jest prawidłowym znakiem. Standardowe operacje we / wy zwracane są EOFpo wykryciu stanu końca pliku - nie jest to znak specjalny.

Nawiasem mówiąc, pliki nie muszą kończyć się znakiem nowej linii (znak wiersza ASCII). Edytory tekstu radzą sobie z plikami, które wszystkie są tekstem do wydrukowania, ale nie mają końca nowej linii.

Thomas Dickey
źródło
8
POSIX definiuje plik tekstowy jako plik zawierający sekwencję linii, a z kolei każdy wiersz jako sekwencję znaków innych niż nowa linia, po której następuje jedna nowa linia. Zatem plik, który kończy się na cokolwiek innego niż 0x0A, nie jest zgodnym plikiem tekstowym.
Damian Yerrick
2
Zdaję sobie z tego sprawę, dlatego wskazałem, że działają edytory tekstu . (Pliki binarne nie mają takiego ograniczenia).
Thomas Dickey,
Naprawdę warto zauważyć, że pliki, które mają być traktowane jako tekst, który nie ma końcowego nowego wiersza, są nadal prawdopodobnie w złej formie (nawet jeśli typowe edytory tekstu zostały zakodowane w celu kompensacji takich plików), przynajmniej jeśli tak naprawdę chcesz szeroko łatwy w obsłudze / kompatybilne, ponieważ brak końcowego znaku nowej linii można dodać dodatkowe trudności w różnych okolicznościach (złączenie / drukowanie wielu plików tekstowych, analizowania z narzędziami typowy wiersza polecenia, minimalnych redaktorów jak busybox„s vi, etc).
mtraceur
(1) Przed VMS RT-11 RSX-11 TOPS-10 miał systemy plików precyzyjne tylko do bloku i potrzebował znaku EOF. Podobnie CP / M, który najwyraźniej skopiował go z DEC, a następnie został skopiowany przez wczesny MS-DOS, a następnie przeszedł do systemu Windows. (2) W Uniksie jest to sterownik tty, a nie powłoka, jak opisano bardziej szczegółowo przez JohanM, chociaż ludzie zwykle uruchamiają powłoki na urządzeniach tty.
dave_thompson_085
Jasne - DEC już tam był (i pamiętaj, że wspomniałem o starszych wersjach). Czy to był początek funkcji CP / M byłby interesującym tematem do zbadania (nie tutaj); Wspomniałem o tych przypadkach, aby dać pewne podstawy alternatywom.
Thomas Dickey,
7

EOF nie jest postacią. Jest to stan, który wskazuje, że nie ma więcej znaków do odczytania ze strumienia pliku. Po wprowadzeniu polecenia EOF z terminala sygnalizujesz systemowi operacyjnemu zamknięcie strumienia wejściowego, nie wpisując specjalnego znaku.

Munir
źródło
1
Tak, ale w tabeli ASCII EOF to 26, więc pomyślałem, że ostatnim bajtem była binarna reprezentacja 26. Więc jak program odczytujący dane wejściowe może wiedzieć, gdzie się kończy?
sworwitz,
ASCII był przeznaczony do przekazywania informacji przez sieć. W takim przypadku potrzebujesz znaku EOF. (ASCII ma również wiele kodów kontrolnych. Nie wszystko można wydrukować.) W przypadku strumieni plików rozmiar pliku jest już znany w systemie plików, więc system operacyjny może stwierdzić, kiedy nie ma już więcej danych do odczytania.
Munir,
@sworwitz: W odniesieniu do C, funkcje odczytu danych wejściowych zwracające znak na wywołanie zwracają liczbę całkowitą (zwykle liczbę 32-bitową, ale muszą mieć minimum 16 bitów), a nie znak. Funkcja sygnalizuje i EOF, zwracając -1 (0xffffffff), która nie jest prawidłową wartością 8-bitową, więc nie zostanie pomylony przez żaden znak ASCII, nawet 0xff. Funkcje zwracające ciąg znaków również zwracają długość odczytanych danych. Ta długość może być użyta do sygnalizowania braku danych lub końca danych (ponownie, długość może wynosić -1). Na koniec jest też funkcja, którą możesz wywołać, która poinformuje cię, czy strumień dobiegł końca
slebetman,
Ok dziękuję! Więc kiedy w bash naciskam Ctrl + d podaję znak ASCII, prawda?
sworwitz,
@sworwitz Niezupełnie. Zanim bashwejdzie w posiadanie danych wejściowych, jest masowany przez sterownik TTY. Ten sterownik przechwytuje Ctrl-D i wysyła EOF do bash (gdzie EOF nie jest postacią, ale specjalnym statusem pliku)
Stig Hemmer