使用系统调用来实现unix cat命令

时间:2010-10-05 18:14:17

标签: c system-calls cat

对于我的OS类,我负责使用系统调用实现Unix的cat命令(没有scanf或printf)。这是我到目前为止所得到的:

(感谢回复)

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

    }

}

我看过的例子只显示了已知字节数的读数。我不知道每个读取文件有多少字节,所以如何指定读取的最后一个参数?

5 个答案:

答案 0 :(得分: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; }

{{1}}

答案 1 :(得分:3)

您需要读取适合缓冲区的字节数。现在,你还没有缓冲区,你所拥有的只是指向缓冲区的指针。这没有被初始化为任何东西。鸡肉和鸡蛋,你因此不知道要读多少字节。

创建一个缓冲区。

答案 2 :(得分:2)

通常无需一口气读取整个文件。选择与主机操作系统的内存页面大小相同或倍数的缓冲区大小是一个好方法。 1或2 X页面大小可能足够好。

使用太大的缓冲区实际上会导致程序运行更糟,因为它们会对虚拟内存系统施加压力并导致分页。

答案 3 :(得分:2)

您可以使用openfstatmmapmadvisewrite来制作非常高效的cat命令。

如果特定于Linux,您可以使用openfstatfadvisesplice来制作更高效的cat命令。

advise调用是指定SEQUENTIAL标志,它将告诉内核对文件进行积极的预读。

如果您希望对系统的其余部分保持礼貌并最大限度地减少缓冲区缓存的使用,您可以使用32 MB左右的块进行复制,并在已读取的部分上使用建议的DONTNEED标记。

注意:

以上只有在源是文件时才有效。如果fstat无法提供大小,那么您必须回退到使用已分配的缓冲区readwrite。您也可以使用splice

答案 4 :(得分:1)

在阅读文件之前,使用stat功能查找文件大小。或者,您可以阅读块,直到获得EOF。