对于我的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);
}
}
我看过的例子只显示了已知字节数的读数。我不知道每个读取文件有多少字节,所以如何指定读取的最后一个参数?
答案 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)
您可以使用open
,fstat
,mmap
,madvise
和write
来制作非常高效的cat命令。
如果特定于Linux,您可以使用open
,fstat
,fadvise
和splice
来制作更高效的cat命令。
advise调用是指定SEQUENTIAL标志,它将告诉内核对文件进行积极的预读。
如果您希望对系统的其余部分保持礼貌并最大限度地减少缓冲区缓存的使用,您可以使用32 MB左右的块进行复制,并在已读取的部分上使用建议的DONTNEED标记。
注意:
以上只有在源是文件时才有效。如果fstat无法提供大小,那么您必须回退到使用已分配的缓冲区read
,write
。您也可以使用splice
。
答案 4 :(得分:1)
在阅读文件之前,使用stat功能查找文件大小。或者,您可以阅读块,直到获得EOF。