Jadi, saya bertanya di sini beberapa waktu yang lalu, tetapi setengah dari pertanyaan itu hanya saya yang bodoh. Dan saya masih memiliki masalah. Saya harap ini akan lebih jelas dari pertanyaan sebelumnya.

Saya sedang menulis POSIX cat, saya hampir berhasil, tetapi saya memiliki beberapa masalah:

  1. cat saya tidak dapat membaca dari pipa dan saya benar-benar tidak tahu mengapa (pengalihan (<) berfungsi dengan baik)

  2. Saya tidak tahu bagaimana membuatnya terus membaca stdin, tanpa beberapa masalah. Saya memiliki versi yang berfungsi "baik", tetapi akan membuat stack-overflow. Versi lain tidak akan berhenti membaca dari stdin jika hanya ada stdin yaitu: my-cat < file akan membaca dari stdin sampai dihentikan yang seharusnya tidak, tetapi harus membaca dari stdin dan menunggu penghentian jika tidak ada file disediakan.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>

int main(int argc, char *argv[])
{
    char opt;
    while ((opt = getopt(argc, argv, "u")) != EOF) {
        switch(opt) {
            case 'u':
                /* Make the output un-buffered */
                setbuf(stdout, NULL);
                break;
            default:
                break;
        }
    }

    argc -= optind;
    argv += optind;

    int i = 0, fildes, fs = 0;

    do {
        /* Check for operands, if none or operand = "-". Read from stdin */
        if (argc == 0 || !strcmp(argv[i], "-")) {
            fildes = STDIN_FILENO;
        } else {
            fildes = open(argv[i], O_RDONLY);
        }

        /* Check for directories */
        struct stat fb;
        if (!fstat(fildes, &fb) && S_ISDIR(fb.st_mode)) {
            fprintf(stderr, "pcat: %s: Is a directory\n", argv[i]);
            i++;
            continue;
        }

        /* Get file size */
        fs = fb.st_size;

        /* If bytes are read, write them to stdout */
        char *buf = malloc(fs * sizeof(char));
        while ((read(fildes, buf, fs)) > 0)
            write(STDOUT_FILENO, buf, fs);

        free(buf);

        /* Close file if it's not stdin */
        if (fildes != STDIN_FILENO)
            close(fildes);

        i++;
    } while (i < argc);

    return 0;
}
1
user419050 12 Mei 2021, 23:06

1 menjawab

Jawaban Terbaik

Pipa tidak memiliki ukuran, dan terminal juga tidak. Isi bidang st_size tidak ditentukan untuk file tersebut. (Di sistem saya sepertinya selalu berisi 0, tapi saya rasa tidak ada jaminan lintas platform untuk itu.)

Jadi rencana Anda untuk membaca seluruh file sekaligus dan menulis semuanya lagi tidak dapat diterapkan untuk file non-reguler, dan bahkan berisiko bagi mereka (pembacaan tidak dijamin mengembalikan jumlah penuh byte yang diminta). Ini juga merupakan babi memori yang tidak perlu jika file besar.

Strategi yang lebih baik adalah membaca ke buffer ukuran tetap, dan hanya menulis jumlah byte yang berhasil Anda baca. Anda ulangi ini sampai end-of-file tercapai, yang ditunjukkan dengan read() mengembalikan 0. Ini adalah bagaimana Anda memecahkan masalah kedua Anda.

Pada catatan yang sama, write() tidak dijamin untuk menuliskan jumlah penuh byte yang Anda minta, jadi Anda perlu memeriksa nilai kembaliannya, dan jika pendek, coba lagi untuk menulis sisa byte.

Berikut ini contohnya:

#define BUFSIZE 65536  // arbitrary choice, can be tuned for performance

ssize_t nread;
char buf[BUFSIZE]; // or char *buf = malloc(BUFSIZE);
while ((nread = read(filedes, buf, BUFSIZE)) > 0) {
    ssize_t written = 0;
    while (written < nread) {
        ssize_t ret = write(STDOUT_FILENO, buf + written, nread - written);
        if (ret <= 0)
            // handle error
        written += ret;
    }
}
if (nread < 0)
    // handle error

Sebagai komentar terakhir, program Anda tidak memiliki pemeriksaan kesalahan secara umum; misalnya jika file tidak dapat dibuka, file akan tetap dilanjutkan dengan filedes == -1. Penting untuk memeriksa nilai pengembalian dari setiap panggilan sistem yang Anda keluarkan, dan menangani kesalahan yang sesuai. Ini akan menjadi penting untuk sebuah program yang akan digunakan dalam kehidupan nyata, dan bahkan untuk program mainan yang dibuat hanya sebagai latihan, akan sangat membantu dalam men-debug mereka. (Pemeriksaan kesalahan mungkin akan memberi Anda beberapa petunjuk dalam mencari tahu apa yang salah dengan program ini, misalnya.)

1
Nate Eldredge 12 Mei 2021, 20:38