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

发布于 2024-09-26 08:55:57 字数 904 浏览 1 评论 0原文

对于我的操作系统课程,我的任务是通过系统调用(无 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);

    }

}

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

For my OS class I have the assignment of implementing Unix's cat command with system calls (no scanf or printf). Here's what I got so far:

(Edited thanks to responses)

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

    }

}

The examples I have seen only show read with a known number of bytes. I don't know how much bytes each of the read files will have, so how do I specify read's last paramether?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

空心空情空意 2024-10-03 08:55:57
  • 到缓冲区之前,您必须分配一个缓冲区。在堆栈上(最简单)或使用 mmap
  • perror 是一个复杂的库函数,而不是系统调用。
  • exit 不是 Linux 上的系统调用。但 _exit 是。
  • 写入的字节数不要超过您之前读取的字节数。
  • 或者,一般来说:阅读有关所有这些系统调用的文档。

编辑:这是我的代码,仅使用系统调用。错误处理有些有限,因为我不想重新实现 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;
}
  • Before you can read into a buffer, you have to allocate one. Either on the stack (easiest) or with mmap.
  • perror is a complicated library function, not a system call.
  • exit is not a system call on Linux. But _exit is.
  • Don't write more bytes than you have read before.
  • Or, in general: Read the documentation on all these system calls.

Edit: Here is my code, using only system calls. The error handling is somewhat limited, since I didn't want to re-implement 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;
}
眼中杀气 2024-10-03 08:55:57

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

创建一个缓冲区。

You need to read as many bytes as will fit in the buffer. Right now, you don't have a buffer yet, all you got is a pointer to a buffer. That isn't initialized to anything. Chicken-and-egg, you therefore don't know how many bytes to read either.

Create a buffer.

慵挽 2024-10-03 08:55:57

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

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

There is usually no need to read the entire file in one gulp. Choosing a buffer size that is the same or a multiple of the host operating system's memory page size is a good way to go. 1 or 2 X the page size is probably good enough.

Using buffers that are too big can actually cause your program to run worse because they put pressure on the virtual memory system and can cause paging.

旧人哭 2024-10-03 08:55:57

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

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

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

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

注意:

以上仅当源是文件时才有效。如果 fstat 无法提供大小,那么您必须回退到使用分配的缓冲区和读取写入。您也可以使用splice

You could use open, fstat, mmap, madvise and write to make a very efficient cat command.

If Linux specific you could use open, fstat, fadvise and splice to make an even more efficient cat command.

The advise calls are to specify the SEQUENTIAL flags which will tell the kernel to do aggressive read-ahead on the file.

If you like to be polite to the rest of the system and minimize buffer cache use, you can do your copy in chunks of 32 megabytes or so and use the advise DONTNEED flags on the parts already read.

Note:

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.

把人绕傻吧 2024-10-03 08:55:57

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

Use the stat function to find the size of your files before you read them. Alternatively, you can read chunks until you get an EOF.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文