EOF bukan simbol

Baru-baru ini, saya membaca buku β€œSistem Komputer: Arsitektur dan Pemrograman. Tampilan programmer. " Di sana, dalam bab tentang sistem Iix O / O, penulis menyebutkan bahwa tidak ada karakter khusus di akhir file EOF. Jika Anda membaca tentang sistem I / O Unix / Linux, atau bereksperimen dengannya, jika Anda menulis program C yang membaca data dari file, maka pernyataan ini mungkin akan tampak sangat jelas bagi Anda. Tetapi mari kita melihat lebih dekat dua pernyataan berikut yang berkaitan dengan apa yang saya temukan dalam buku ini:





  1. EOF - ini bukan simbol.
  2. Tidak ada karakter khusus di akhir file.

Apa ini EOF?

EOF bukan simbol


Mengapa seseorang mengatakan atau berpikir bahwa EOFini adalah simbol? Saya kira ini mungkin karena beberapa program yang ditulis dalam C dapat menemukan kode yang menggunakan pemeriksaan eksplisit untuk EOFmenggunakan fungsi getchar()dan getc().

Mungkin terlihat seperti ini:

    #include <stdio.h>
    ...
    while ((c = getchar()) != EOF)
      putchar(c);

Atau lebih:

    FILE *fp;
    int c;
    ...
    while ((c = getc(fp)) != EOF)
      putc(c, stdout);

Jika Anda melihat bantuan untuk getchar()atau getc(), Anda dapat mengetahui bahwa kedua fungsi membaca karakter berikutnya dari aliran input. Mungkin - inilah tepatnya yang menyebabkan kesalahpahaman tentang alam EOF. Tapi ini hanya asumsi saya. Mari kita kembali ke gagasan bahwa EOF- ini bukan simbol.

Dan apakah simbol secara umum? Simbol adalah komponen teks terkecil. "A", "a", "B", "b" - semua ini adalah simbol yang berbeda. Karakter memiliki kode numerik, yang dalam standar Unicode disebut titik kode . Misalnya, huruf Latin "A" memiliki, dalam desimal, kode 65. Ini dapat dengan cepat diperiksa menggunakan baris perintah interpreter Python:

$python
>>> ord('A')
65
>>> chr(65)
'A'

Atau Anda bisa melihat tabel ASCII di Unix / Linux:

$ man ascii


Kita akan menemukan kode mana yang sesuai EOFdengan menulis sebuah program kecil dalam C. Dalam ANSI C, konstanta EOFdidefinisikan stdio.h, itu adalah bagian dari perpustakaan standar. Biasanya ditulis untuk konstanta ini -1. Anda dapat menyimpan kode berikut dalam file printeof.c, kompilasi dan jalankan:

#include <stdio.h>

int main(int argc, char *argv[])
{
  printf("EOF value on my system: %d\n", EOF);
  return 0;
}

Kompilasi dan jalankan program:

$ gcc -o printeof printeof.c

$ ./printeof
EOF value on my system: -1

Saya memiliki program ini, diuji pada Mac OS dan di Ubuntu, laporan yang EOFsama -1. Apakah ada karakter dengan kode ini? Di sini, sekali lagi, Anda dapat memeriksa kode karakter dalam tabel ASCII, Anda dapat melihat tabel Unicode dan mencari tahu dalam kisaran apa kode karakter dapat. Kami akan bertindak secara berbeda: kami akan memulai juru bahasa Python dan menggunakan fungsi standar chr()untuk memberi kami simbol yang sesuai dengan kode -1:

$ python
>>> chr(-1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: chr() arg not in range(0x110000)

Seperti yang diharapkan, karakter dengan kode -1tidak ada. Jadi, pada akhirnya, EOFdan kebenaran bukanlah simbol. Kami sekarang beralih ke pernyataan kedua yang sedang dipertimbangkan.

Tidak ada karakter khusus di akhir file.


Mungkin EOF- ini adalah karakter khusus yang dapat ditemukan di akhir file? Saya kira Anda sudah tahu jawabannya. Tapi mari kita teliti asumsi kita.

Ambil file teks sederhana, helloworld.txt , dan tampilkan isinya dalam representasi heksadesimal. Untuk melakukan ini, Anda dapat menggunakan perintah xxd:

$ cat helloworld.txt
Hello world!

$ xxd helloworld.txt
00000000: 4865 6c6c 6f20 776f 726c 6421 0a         Hello world!.

Seperti yang Anda lihat, karakter terakhir file memiliki kode 0a. Dari tabel ASCII, Anda dapat mengetahui bahwa kode ini sesuai dengan karakter nl, yaitu, dengan karakter baris baru. Anda bisa mengetahui ini menggunakan Python:

$ python
>>> chr(0x0a)
'\n'

Begitu. EOF- Ini bukan simbol, dan pada akhir file tidak ada simbol khusus. Apa ini EOF?

Apa itu EOF?


EOF(end-of-file) adalah keadaan yang dapat dideteksi oleh aplikasi dalam situasi di mana operasi membaca file mencapai akhirnya.

Mari kita lihat bagaimana Anda dapat mendeteksi keadaan EOFdalam berbagai bahasa pemrograman saat membaca file teks menggunakan alat input-output tingkat tinggi yang disediakan oleh bahasa-bahasa ini. Untuk melakukan ini, kami akan menulis versi yang sangat sederhana cat, yang akan dipanggil mcat. Bunyinya byte teks (karakter) ASCII dan secara eksplisit memeriksa EOF. Kami akan menulis program dalam bahasa berikut:

  • ANSI C
  • Python 3
  • Pergilah
  • JavaScript (Node.js)

Ini adalah repositori dengan kode sampel. Kami melanjutkan ke analisis mereka.

ANSI C


Mari kita mulai dengan Yang Mulia C. Program yang disajikan di sini adalah versi modifikasi catdari buku "Bahasa Pemrograman C."

/* mcat.c */
#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;
}

Kompilasi:

$ gcc -o mcat mcat.c

Meluncurkan:

$ ./mcat helloworld.txt
Hello world!

Berikut adalah beberapa penjelasan mengenai kode di atas:

  • Program membuka file yang diteruskan ke sana sebagai argumen baris perintah.
  • Loop whilemenyalin data dari file ke aliran output standar. Data disalin byte demi byte, ini terjadi hingga akhir file tercapai.
  • Ketika program mencapai EOF, itu menutup file dan keluar.

Python 3


Dalam Python, tidak ada mekanisme untuk memeriksa secara eksplisit EOF, mirip dengan yang tersedia di ANSI C. Tetapi jika Anda membaca karakter file dengan karakter, Anda dapat mengungkapkan status EOFjika variabel yang menyimpan karakter berikutnya dibaca kosong:

# 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='')

Jalankan program dan lihat hasil yang dikembalikan ke sana:

$ python mcat.py helloworld.txt
Hello world!

Ini adalah versi yang lebih pendek dari contoh yang sama yang ditulis dengan Python 3.8+. Di sini operator digunakan : = (ini disebut "operator walrus" atau "operator walrus"):

# mcat38.py
import sys

with open(sys.argv[1]) as fin:
    while (c := fin.read(1)) != '':  #   1    EOF
        print(c, end='')

Jalankan kode ini:

$ python3.8 mcat38.py helloworld.txt
Hello world!

Pergilah


Di Go, Anda dapat secara eksplisit memeriksa kesalahan yang dikembalikan oleh Read () untuk melihat apakah itu mengindikasikan bahwa kami sampai di akhir file:

// mcat.go
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// 1-byte buffer
    for {
        bytesread, err := file.Read(buffer)
        if err == io.EOF {
            break
        }
        fmt.Print(string(buffer[:bytesread]))
    }
    file.Close()
}

Jalankan program:

$ go run mcat.go helloworld.txt
Hello world!

JavaScript (Node.js)


Node.js tidak memiliki mekanisme untuk memeriksa secara eksplisit EOF. Tetapi, ketika, setelah mencapai akhir file, upaya dilakukan untuk membaca sesuatu yang lain, acara aliran akhir dimunculkan .

/* mcat.js */
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); /* chunk is one byte */
  }
});

readable.on('end', () => {
  console.log('\nEOF: There will be no more data.');
});

Jalankan program:

$ node mcat.js helloworld.txt
Hello world!

EOF: There will be no more data.

Mekanisme sistem tingkat rendah


Bagaimana mekanisme I / O tingkat tinggi yang digunakan dalam contoh di atas menentukan akhir file? Di Linux, mekanisme ini secara langsung atau tidak langsung menggunakan panggilan sistem read () yang disediakan oleh kernel. Fungsi (atau makro) getc()dari C, misalnya, menggunakan pemanggilan sistem read()dan kembali EOFjika itu read()menunjukkan terjadinya suatu keadaan mencapai akhir file. Dalam hal ini, read()kembali 0. Jika Anda menggambarkan semua ini dalam bentuk diagram, Anda mendapatkan yang berikut:


Ternyata fungsi ini getc()didasarkan pada read().

Kami akan menulis versi catbernama syscathanya menggunakan panggilan sistem Unix. Kami akan melakukan ini tidak hanya karena minat, tetapi juga karena mungkin akan bermanfaat bagi kami.

Berikut ini program yang ditulis dalam C:

/* syscat.c */
#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;
}

Menjalankannya:

$ gcc -o syscat syscat.c

$ ./syscat helloworld.txt
Hello world!

Kode ini menggunakan fakta bahwa fungsi read(), yang mengindikasikan akhir file tercapai, kembali 0.

Berikut adalah program yang sama yang ditulis dengan Python 3:

# 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)

Menjalankannya:

$ python syscat.py helloworld.txt
Hello world!

Ini adalah hal yang sama yang ditulis dengan Python 3.8+:

# 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)

Jalankan kode ini juga:

$ python3.8 syscat38.py helloworld.txt
Hello world!

Ringkasan


  • EOF - ini bukan simbol.
  • Tidak ada karakter khusus di akhir file.
  • EOF - ini adalah keadaan yang dilaporkan kernel, dan yang dapat dideteksi oleh aplikasi ketika operasi pembacaan data mencapai akhir file.
  • Dalam ANSI C EOF, ini lagi bukan karakter. Ini adalah konstanta yang didefinisikan stdio.hdi mana nilai -1 biasanya ditulis.
  • "Karakter" EOFtidak dapat ditemukan dalam tabel ASCII atau di Unicode.

Pembaca yang budiman! Apakah Anda tahu tentang kesalahpahaman yang lebih atau kurang tersebar luas dari dunia komputer?


All Articles