1

I am trying to read a file into a string all at once, however I have only been able to read it in line by line with this code:

int main()
{
    char input[1000000];
    FILE *fPointer;

    fPointer = fopen("/Users/boys/users.json", "r");

    if( fPointer != NULL)
    {
        while(!feof(fPointer))
        {
            fgets(input, 1000000, fPointer);
            //printf("%s", input);

        }

    }
    printf("%s", input);

    return 0;
}

I am dealing with a json file and have only used csv and simpler files in the past with c as I am still quite new to it and not all that good so if anyone has a simple solution to reading a file in all at once rather than line by line that would be a great help, thanks!

gsamaras
  • 71,951
  • 46
  • 188
  • 305
Aaron
  • 21
  • 5
  • As you can see I tried printing the file contents outside of the loop which showed me I was not reading it in all at once – Aaron Aug 29 '17 at 11:17
  • [ { "id": 1, "name": "Leanne Graham", "username": "Bret", "email": "Sincere@april.biz", "address": { "street": "Kulas Light", "suite": "Apt. 556", "city": "Gwenborough", "zipcode": "92998-3874", "geo": { "lat": "-37.3159", "lng": "81.1496" } }, "phone": "1-770-736-8031 x56442", "website": "hildegard.org", "company": { "name": "Romaguera-Crona", "catchPhrase": "Multi-layered client-server neural-net", "bs": "harness real-time e-markets" } }, – Aaron Aug 29 '17 at 11:18
  • 5
    Open the file, seek to the end, get the file position (which is equal to the size), rewind file position, allocate memory, read file into allocated memory. Done. – Some programmer dude Aug 29 '17 at 11:18
  • that's a part of it – Aaron Aug 29 '17 at 11:19
  • 1
    fread() function help You. Divide text with dots and commas, is hard to understand – Jacek Cz Aug 29 '17 at 11:19
  • 4
    As for your current code, I suggest you take some time to read [Why is “while ( !feof (file) )” always wrong?](https://stackoverflow.com/questions/5431941/why-is-while-feof-file-always-wrong) – Some programmer dude Aug 29 '17 at 11:19
  • 1
    `while(!feof(fPointer))` That won't work like you think it does. – Andrew Henle Aug 29 '17 at 11:20

4 Answers4

3

fgets() function reads until it reach EOF / NewLine / Specified size. So its not right function to use because you can read max one line if file contains more than one line.

Here one possible way

First you have to find out size (in bytes) of content in file

fseek(fPointer, 0L, SEEK_END);
long numOfBytes = ftell(fPointer);

Than dynamically allocate buffer big enough for this amount of data. (Since you can use VLA)

char *ptr = calloc(numOfBytes+1, 1);
if (ptr == NULL) // Failed to allocate memory
   { perror("calloc"); exit(EXIT_FAILURE); };

Reset position of indicator to the beginning of file (or reopen file)

fseek(fPointer, 0L, SEEK_SET); // Or use rewind

Now you may read whole content of file using fread.

fread(ptr, sizeof(char), numOfBytes, fPointer);

And clean up

free(ptr);
fclose(fPointer);
Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
kocica
  • 6,412
  • 2
  • 14
  • 35
1

From man fgets:

fgets() reads in at most one less than size characters from stream and stores them into the buffer pointed to by s. Reading stops after an EOF or a newline. If a newline is read, it is stored into the buffer. A terminating null byte ('\0') is stored after the last character in the buffer.

You can use fread to achieve what you want.

1
  1. Open the file (FILE *fPointer = fopen("/Users/boys/users.json", "r");).
  2. Seek it to the end (fseek(fPointer , 0, SEEK_END);).
  3. Get the file position (which is equal to the size).
  4. Rewind the file position.
  5. Allocate the memory needed.
  6. Read file into allocated memory.
  7. Use the string.
  8. De-allocate the memory when you are done.

PS: Reading the file via fread() does not form a string as it may lack a null character (but you can always insert it yourself).

gsamaras
  • 71,951
  • 46
  • 188
  • 305
0

On a POSIX-compliant system:

int fd = open( filename, O_RDONLY );

struct stat sb;
fstat( fd, sb );

// by adding one, data can possibly be
// treated as a string, assuming no NULs
// exist in the file's contents
char *data = calloc( sb.st_size + 1, 1 );

size_t totalRead = 0;

while ( totalRead < sb.st_size )
{
    ssize_t bytesRead = read( fd, &( data[ totalRead ] ), sb.st_size - totalRead );
    if ( bytesRead <= 0 )
    {
        break;
    }

    totalRead += bytesRead;
}

I used calloc() to create a zero-filled buffer instead of explicitly setting the last byte to NUL. That makes the actual processing a bit easier to see and understand.

I also left out error checking for the same reason.

Andrew Henle
  • 32,625
  • 3
  • 24
  • 56
  • Hmm, downvoter apparently doesn't like simple, standards-compliant code that works. – Andrew Henle Aug 29 '17 at 12:19
  • NMDV, Only unexplained weakness I see is the casual conversions between the _unsigned_ `size_t` and _signed_ `off_t` and their potential different range effects. – chux - Reinstate Monica Aug 29 '17 at 15:14
  • @chux Blame POSIX. There's no real easy, concise way to get around the fact that POSIX uses `off_t` for a file size in `struct stat`, and `size_t` for an argument to `read()`, which then returns `ssize_t`, all to refer to the same type of value - a number of bytes. – Andrew Henle Aug 29 '17 at 15:25
  • This is probably bad etiquette, but I upvoted this to counteract the unexplained downvote. In general, however, is there a significant difference beween using st_size, and seeking to end-of file? I would expect the internal implementations to be pretty similar. – Kevin Boone Aug 30 '17 at 14:28