2010-10-05 3 views
4

Для моего класса ОС у меня есть назначение реализации команды cat для Unix с системными вызовами (без scanf или printf). Вот что я получил до сих пор:Использование системных вызовов для реализации команды unix cat

(Отредактированный благодаря ответам)

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



main(void) 
{ 


    int fd1; 
    int fd2; 

    char *buffer1; 
    buffer1 = (char *) calloc(100, sizeof(char)); 


    char *buffer2; 
    buffer2 = (char *)calloc(100, sizeof(char)); 

    fd1 = open("input.in", O_RDONLY);  
    fd2 = open("input2.in", O_RDONLY); 


    while(eof1){ //<-lseek condition to add here 
    read (fd1, buffer1, /*how much to read here?*/); 
    write(1, buffer1, sizeof(buffer1)-1);  
    } 


    while (eof2){ 

    read (fd2,buffer2, /*how much to read here?*/); 
    write(1, buffer2, sizeof(buffer2)-1); 

    } 

} 

примеров, которые я видел только показать прочтение с известным числом байт. Я не знаю, сколько байтов будет иметь каждый из файлов чтения, так как я могу указать последний параметр прочтения чтения?

+0

Мой [ответ] (http://stackoverflow.com/questions/3866217/how-can-i-make-the-system-call-write-print-to-the-screen/3866557#3866557) на ваш [предыдущий вопрос] (http://stackoverflow.com/questions/3866217/how-can-i-make-the-system-call-write-print-to-the-screen) может быть уместным в вашем стремлении реализовать * cat *, используя только системные вызовы. – jschmier

ответ

4
  • Прежде чем вы сможете добавить read в буфер, вы должны выделить его. Либо в стек (проще), либо с mmap.
  • perror - сложная библиотечная функция, а не системный вызов.
  • exit не является системным вызовом в Linux. Но _exit есть.
  • Не write больше байтов, чем было у вас есть read.
  • Или, в общем: прочитайте документацию по всем этим системным вызовам.

Редактировать: Вот мой код, используя только системные вызовы. Обработка ошибок несколько ограничена, так как я не хотел повторно реализовывать perror.

#include <fcntl.h> 
#include <unistd.h> 

static int 
cat_fd(int fd) { 
    char buf[4096]; 
    ssize_t nread; 

    while ((nread = read(fd, buf, sizeof buf)) > 0) { 
    ssize_t ntotalwritten = 0; 
    while (ntotalwritten < nread) { 
     ssize_t nwritten = write(STDOUT_FILENO, buf + ntotalwritten, nread - ntotalwritten); 
     if (nwritten < 1) 
     return -1; 
     ntotalwritten += nwritten; 
    } 
    } 

    return nread == 0 ? 0 : -1; 
} 

static int 
cat(const char *fname) { 
    int fd, success; 

    if ((fd = open(fname, O_RDONLY)) == -1) 
    return -1; 

    success = cat_fd(fd); 

    if (close(fd) != 0) 
    return -1; 

    return success; 
} 


int 
main(int argc, char **argv) { 
    int i; 

    if (argc == 1) { 
    if (cat_fd(STDIN_FILENO) != 0) 
     goto error; 
    } else { 
    for (i = 1; i < argc; i++) { 
     if (cat(argv[i]) != 0) 
     goto error; 
    } 
    } 
    return 0; 

error: 
    write(STDOUT_FILENO, "error\n", 6); 
    return 1; 
} 
+0

Перро и выход не имеют значения. там есть только printf и scanf. – andandandand

+0

@omgzor - тогда вы действительно не «выполняете команду кошки Unix исключительно с системными вызовами» – jschmier

+0

Я все равно их вытащил, чтобы избежать дальнейшего упоминания вещи в ответах. – andandandand

0

Используйте функцию stat, чтобы найти размер ваших файлов, прежде чем вы их прочитаете. Кроме того, вы можете читать куски, пока не получите EOF.

3

Вам необходимо прочитать столько байтов, сколько поместится в буфер. Прямо сейчас у вас еще нет буфера, все, что у вас есть, - это указатель на буфер. Это ничего не инициализирует. Курица-яйцо, поэтому вы не знаете, сколько байтов читать.

Создать буфер.

+0

С каким размером? c = (char *) calloc (100, sizeof (char)); – andandandand

+0

Вот что я имею в своем путеводителе. Он задает 100 символов, если вы не знаете, сколько символов имеет файл, который вы бы наложили на calloc? – andandandand

+1

Обычно вы можете использовать более крупный буфер, но 100 сделают это. Просто используйте цикл для чтения фрагмента в этот буфер и напишите эту часть в stdout (read() расскажет вам, сколько она фактически заполнена в буфере, поэтому не пишите больше, чем в каждом цикле) – nos

2

Обычно нет необходимости читать весь файл за один глоток. Выбор размера буфера, который является таким же или кратным размеру страницы памяти операционной системы хоста, является хорошим способом. 1 или 2 X размер страницы, вероятно, достаточно хорош.

Использование слишком больших буферов может привести к ухудшению работы вашей программы, поскольку они оказывают давление на систему виртуальной памяти и могут вызывать пейджинг.

2

Вы можете использовать open, fstat, mmap, madvise и write сделать эффективную команду кошки очень.

Если Linux конкретнее вы могли бы использовать open, fstat, fadvise и splice сделать еще более эффективной команды кошки.

Рекомендованные вызовы - это указать SEQUENTIAL флаги, которые будут сообщать ядру о агрессивном прочтении файла.

Если вам нравится быть вежливым с остальной частью системы и минимизировать использование кеша буфера, вы можете сделать свою копию в кусках по 32 мегабайта или около того и использовать рекомендуемые флаги DONTNEED на уже прочитанных частях.

Примечание:

выше будет работать только тогда, когда источником является файл. Если fstat не предоставит размер, вы должны вернуться к использованию выделенного буфера и read, write. Вы также можете использовать splice.

Смежные вопросы