4

对于我的操作系统类,我的任务是使用系统调用(没有 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);

    }

}

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

4

5 回答 5

4
  • read进入缓冲区之前,您必须分配一个。在堆栈上(最简单)或使用mmap.
  • perror是一个复杂的库函数,而不是系统调用。
  • exit不是 Linux 上的系统调用。但是_exit是。
  • 不要writeread以前更多的字节。
  • 或者,一般来说:阅读所有这些系统调用的文档。

编辑:这是我的代码,仅使用系统调用。错误处理有些有限,因为我不想重新实现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;
}
于 2010-10-05T18:18:17.107 回答
3

您需要读取缓冲区中容纳的尽可能多的字节。现在,你还没有缓冲区,你得到的只是一个指向缓冲区的指针。那没有初始化为任何东西。鸡和蛋,因此您也不知道要读取多少字节。

创建一个缓冲区。

于 2010-10-05T18:18:19.163 回答
2

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

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

于 2010-10-05T18:48:34.060 回答
2

您可以使用open, fstat, mmap,madvisewrite来创建一个非常有效的 cat 命令。

如果特定于 Linux ,您可以使用open、和来制作更有效的 cat 命令。fstatfadvisesplice

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

如果您想对系统的其余部分保持礼貌并尽量减少缓冲区缓存的使用,您可以以 32 兆字节左右的大小进行复制,并在已读取的部分上使用建议 DONTNEED 标志。

笔记:

The above will only work if the source is a file. If the fstat fails to provide a size then you must fall back to using an allocated buffer and read, write. You can use splice too.

于 2010-10-05T19:13:22.110 回答
1

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

于 2010-10-05T18:16:24.887 回答