开发者

What is the most efficient way to print a file in C to stdout?

开发者 https://www.devze.com 2023-01-04 17:06 出处:网络
I\'m stuck on this. Currently I\'m using: FILE *a = fopen(\"sample.txt\", \"r\"); int n; while ((n = fgetc(a)) != EOF) {

I'm stuck on this. Currently I'm using:

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

However this method seems to be a bit inefficient. Is there any better way? I tried using fgets:

char *s;
开发者_如何学编程fgets(s, 600, a);
puts(s);

There's one thing I find wrong about this second method, which is that you would need a really large number for the second argument of fgets.

Thanks for all the suggestions. I found a way (someone on IRC told me this) using open(), read(), and 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; }
}


The second code is broken. You need to allocate a buffer, e.g.:

char s[4096];
fgets(s, sizeof(s), a);

Of course, this doesn't solve your problem.

Read fix-size chunks from the input and write out whatever gets read in:

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

You might also want to check ferror(a) in case it stopped for some other reason than reaching EOF.

Notes

  1. I originally used a 4096 byte buffer because it is a fairly common page size for memory allocation and block size for the file system. However, the sweet-spot on my Linux system seems to be around the 64 kB mark, which surprised me. Perhaps CPU cache is a factor here, but I'm just guessing.
  2. For a cold cache, it makes almost no difference, since I/O paging will dominate; even one byte at a time runs at about the same speed.


The most efficient method will depend greatly on the operating system. For example, in Linux, you can use sendfile:

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

This does the copy directly in the kernel, minimizing unnecessary memory-to-memory copies. Other platforms may have similar approaches, such as write()ing to stdout from a mmaped buffer.


I believe the FILE returned by fopen is tipically (always?) buffered, so you first example is not so inefficient as you may think.

The second might perform a little better... if you correct the errors: remember to allocate the buffer, and remember that puts add a newline!.

Other option is to use binary reads (fread).


It all depends on what you want to do with the data.

this will crash though:

char *s;
fgets(s, 600, a);
puts(s);

since s is no buffer, just a pointer somewhere.

One way is to read in the whole file into a buffer and work with that by using fread()

filebuffer = malloc(filelength);
fread( buffer, 1, filelength, fp );


What you're doing is plenty good enough in 99% of applications. Granted, in most C libraries, stdio performs badly, and you'd be better off with Phong Vo's sfio library. If you have measurements showing this is a bottleneck, the natural next step is to allocate a buffer and use fread/fwrite. You don't want fgets because you don't care about newlines.


First make it run, then make it right. You probably don't have to make it fast.

0

精彩评论

暂无评论...
验证码 换一张
取 消