-2

Possible Duplicate:
Easiest way to get file's contents in C

I saw this post but I still feel it involves fseek, ftell etc. And I saw a few other methods where they use feof+fgetc combination but they say feof is not a good option for loop condition. And some other suggest using fgets and reading line by line which I consider as tedious.

Are there any other shorter methods to read entire file contents?

PS: By shorter I mean lines of code.

Community
  • 1
  • 1
Pavan Manjunath
  • 27,404
  • 12
  • 99
  • 125
  • this is an exact duplicate to the question you linked. – moooeeeep Apr 19 '12 at 19:54
  • You dismiss most C APIs in your question. What use is it asking, if you don't want certain APIs to be used? Otherwise, what makes your question different from the one linked to, is that you specifically mention lines of code, so it is a little different, but not much. I am not going to vote close, but I am tempted. – Prof. Falken Apr 19 '12 at 20:56
  • Thanks @IuliusCæsar, I flipped and changed my mind. Upvoted your comment. – Prof. Falken Apr 19 '12 at 20:59
  • @Stacker, read that meta link from Iulius Caesar too. – Prof. Falken Apr 19 '12 at 21:01

2 Answers2

2

Either use mmap() or do it yourself.

Omitting error checking, roughly:

int fd = open(filename, O_RDONLY);
struct stat sb;
fstat(fd, &sb);
char *contents = mmap(0, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);

This is a readonly copy of the file, allocated at an address of the kernel's choosing. If you're on a 32-bit system, you may have to worry about files bigger than 2 GiB. I don't think you can portably avoid using something like fstat() to get the file size. If you want to grow the file, you can specify a larger size than the file size, according to the POSIX specification.

If you DIY, then the first three lines are the same. Then you use:

char *contents = malloc(sb.st_size);
read(fd, contents, sb.st_size);

As noted before, all error checking was omitted in these examples; don't risk it in production-ready code.


I went digging for some more nearly production-ready code that uses mmap() and found:

static int sqs_mapfile(const char *file)
{
    int   fd;
    void *vp;
    struct stat sb;

    if (file == 0)
        return(SQS_NOSQSFILE);
    if ((fd = open(file, O_RDONLY, 0)) < 0)
        return(SQS_OPENFAIL);
    if (fstat(fd, &sb) != 0)
    {
        close(fd);
        return(SQS_STATFAIL);
    }
    vp = mmap(0, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
    close(fd);
    if (vp == MAP_FAILED)
        return(SQS_MMAPFAIL);

The 'SQS_xyz' codes are specific to the program it comes from (as is the function name). This code uses a 3-argument open() call where a 2-argument version is sufficient.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • use this, this is the way to do it!!!! – lukecampbell Apr 19 '12 at 19:51
  • would it be necessary to free the memory returned by `mmap()` in the end? – moooeeeep Apr 19 '12 at 21:01
  • You should `munmap()` the memory when you're done with it if you're using `mmap()`, though if the program is about to exit, that clean up will happen anyway. OTOH, if you might have a list of files to process, you would release the memory for each file once you're done with it. You can use read/write memory mapping if you're going to modify the data and want it recorded. Look at the meanings of the PROT and MAP flags that are available on your machine. Similar comments apply to the `malloc()` and `free()` solution. It is cleanest to release the memory and close the file descriptor ASAP. – Jonathan Leffler Apr 19 '12 at 22:14
1

I think about the shortest way that stands a decent chance of actually working is something on this order:

char *buffer;
size_t size;

fseek(your_file, 0, SEEK_END);
size = ftell(your_file);
rewind(your_file);
buffer = malloc(length);
fread(buffer, 1, length, your_file);

Of course, you only need that once:

char *read_file(FILE *file) { 
    char *buffer;
    size_t size;

    fseek(your_file, 0, SEEK_END);
    size = ftell(your_file);
    rewind(your_file);
    buffer = malloc(length);
    if (buffer) fread(buffer, 1, length, your_file);
    return buffer;
}

Then it's just: char *file_content = read_file(some_file);

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111