将文件打印到stdout的最有效方法是什么?

Spr*_*eet 4 c file

我坚持这个.目前我正在使用:

FILE *a = fopen("sample.txt", "r");
int n;
while ((n = fgetc(a)) != EOF) {
  putchar(n);
}
Run Code Online (Sandbox Code Playgroud)

然而,这种方法似乎有点低效.有没有更好的方法?我尝试使用fgets:

char *s;
fgets(s, 600, a);
puts(s);
Run Code Online (Sandbox Code Playgroud)

对于第二种方法,我发现有一件事是错误的,即对于fgets的第二个参数,你需要一个非常大的数字.

感谢所有的建议.我找到了一种方法(IRC上有人告诉我这个)使用open(),read()和write().

char *filename = "sample.txt";
char buf[8192];
int r = -1;
int in = open(filename, O_RDONLY), out = 0;
if (in == -1)
  return -1;
while (1) {
  r = read(in, buf, sizeof(buf));
  if (r == -1 || r == 0) { break; }
  r = write(out, buf, r);
  if (r == -1 || r == 0) { break; }
}
Run Code Online (Sandbox Code Playgroud)

Mar*_*tos 9

第二个代码被破坏了.你需要分配一个缓冲区,例如:

char s[4096];
fgets(s, sizeof(s), a);
Run Code Online (Sandbox Code Playgroud)

当然,这并不能解决您的问题.

从输入中读取修复大小的块并写出读入的内容:

int n;
char s[65536];
while ((n = fread(s, 1, sizeof(s), a))) {
    fwrite(s, 1, n, stdout);
}
Run Code Online (Sandbox Code Playgroud)

您可能还想检查ferror(a)它是否由于某些其他原因而停止而不是达到EOF.

笔记

  1. 我最初使用4096字节缓冲区,因为它是一个相当常见的页面大小,用于文件系统的内存分配和块大小.然而,我的Linux系统上的最佳点似乎是64 kB标记,这让我感到惊讶.也许CPU缓存是一个因素,但我只是在猜测.
  2. 对于冷缓存,它几乎没有区别,因为I/O分页将占主导地位; 甚至一次一个字节以大约相同的速度运行.

  • 实际上,这是一个非常好的答案.页面大小和磁盘块大小的倍数对性能非常有利.您可能想要测试其他倍数,我已经获得了非常好的结果,65536用于磁盘到磁盘副本. (2认同)

bdo*_*lan 5

最有效的方法将在很大程度上取决于操作系统.例如,在Linux中,您可以使用sendfile:

struct stat buf;
int fd = open(filename, O_RDONLY);
fstat(fd, &buf);
sendfile(0, fd, NULL, buf.st_size);
Run Code Online (Sandbox Code Playgroud)

这样可以直接在内核中进行复制,从而最大限度地减少不必要的内存到内存副本.其他平台可能有类似的方法,例如write()mmaped缓冲区转到stdout .

  • 我相信 `sendfile` 可以用于其他文件描述符。splice 和 Friends 只能与 fifo 之间的任何一个一起工作。 (2认同)