Reading a file and storing all the data in a buffer

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;







up vote
2
down vote

favorite












I wrote a function to read the entire content of a file and return a pointer to an allocated bufer containing all the data.



Please could you tell me if there is a better way of doing this ? One solution could be to use stat() to pre-allocate a buffer and do only one read() call but I don't know if it's better, any though ?



#include <stdio.h>
#include <memory.h>

char *file_read(const char *path, size_t *file_size)

FILE *file = fopen(path, "r");
char buffer[FILE_READ_BUFFER_SIZE];
char *tmp = NULL;
char *data = NULL; // The buffer containing the data of the file
char *data_cursor = NULL; // The current position in the data buffer
size_t data_size = 0; // The size of the data buffer
size_t n = 0; // The number of bytes read by fread()

if (file == NULL)
goto error;

while ((n = fread(buffer, sizeof(char), sizeof(buffer), file)) > 0)
if (data == NULL)
data = malloc(sizeof(char) * n);
data_cursor = data;
data_size = n;
else
// We compute the position in the buffer as an integer
// to be able to re-apply after realloc(). Because realloc()
// can move the pointer we need this position as an integer.
size_t cursor_pos = data_cursor - data;
tmp = realloc(data, sizeof(char) * data_size + n);
if (tmp == NULL)
goto error;
data = tmp;
data_cursor = data + cursor_pos;
data_size += n;

memcpy(data_cursor, buffer, n);


if (ferror(file))
goto error;

fclose(file);
if (file_size != NULL)
*file_size = data_size;
return data;

error:
if (file != NULL)
fclose(file);
if (data != NULL)
free(data);
return NULL;







share|improve this question

















  • 1




    Code posted to codereview should compile, it would be great if you could make this a complete file especially could you post the code for error_set_from_errno_ptr() ?
    – Harald Scheirich
    Jan 24 at 13:45










  • It's just a utility function which stores internally the last errrno & strerror() and return NULL. I replaced it with return NULL in my example. Thanks !
    – Thibaut D.
    Jan 24 at 14:48










  • Here you find how to find size of a file using fseek+ftell, and then allocating a buffer that exact size: stackoverflow.com/questions/5957845/… After that use rewind and fread.
    – Andreas
    Jan 24 at 18:46
















up vote
2
down vote

favorite












I wrote a function to read the entire content of a file and return a pointer to an allocated bufer containing all the data.



Please could you tell me if there is a better way of doing this ? One solution could be to use stat() to pre-allocate a buffer and do only one read() call but I don't know if it's better, any though ?



#include <stdio.h>
#include <memory.h>

char *file_read(const char *path, size_t *file_size)

FILE *file = fopen(path, "r");
char buffer[FILE_READ_BUFFER_SIZE];
char *tmp = NULL;
char *data = NULL; // The buffer containing the data of the file
char *data_cursor = NULL; // The current position in the data buffer
size_t data_size = 0; // The size of the data buffer
size_t n = 0; // The number of bytes read by fread()

if (file == NULL)
goto error;

while ((n = fread(buffer, sizeof(char), sizeof(buffer), file)) > 0)
if (data == NULL)
data = malloc(sizeof(char) * n);
data_cursor = data;
data_size = n;
else
// We compute the position in the buffer as an integer
// to be able to re-apply after realloc(). Because realloc()
// can move the pointer we need this position as an integer.
size_t cursor_pos = data_cursor - data;
tmp = realloc(data, sizeof(char) * data_size + n);
if (tmp == NULL)
goto error;
data = tmp;
data_cursor = data + cursor_pos;
data_size += n;

memcpy(data_cursor, buffer, n);


if (ferror(file))
goto error;

fclose(file);
if (file_size != NULL)
*file_size = data_size;
return data;

error:
if (file != NULL)
fclose(file);
if (data != NULL)
free(data);
return NULL;







share|improve this question

















  • 1




    Code posted to codereview should compile, it would be great if you could make this a complete file especially could you post the code for error_set_from_errno_ptr() ?
    – Harald Scheirich
    Jan 24 at 13:45










  • It's just a utility function which stores internally the last errrno & strerror() and return NULL. I replaced it with return NULL in my example. Thanks !
    – Thibaut D.
    Jan 24 at 14:48










  • Here you find how to find size of a file using fseek+ftell, and then allocating a buffer that exact size: stackoverflow.com/questions/5957845/… After that use rewind and fread.
    – Andreas
    Jan 24 at 18:46












up vote
2
down vote

favorite









up vote
2
down vote

favorite











I wrote a function to read the entire content of a file and return a pointer to an allocated bufer containing all the data.



Please could you tell me if there is a better way of doing this ? One solution could be to use stat() to pre-allocate a buffer and do only one read() call but I don't know if it's better, any though ?



#include <stdio.h>
#include <memory.h>

char *file_read(const char *path, size_t *file_size)

FILE *file = fopen(path, "r");
char buffer[FILE_READ_BUFFER_SIZE];
char *tmp = NULL;
char *data = NULL; // The buffer containing the data of the file
char *data_cursor = NULL; // The current position in the data buffer
size_t data_size = 0; // The size of the data buffer
size_t n = 0; // The number of bytes read by fread()

if (file == NULL)
goto error;

while ((n = fread(buffer, sizeof(char), sizeof(buffer), file)) > 0)
if (data == NULL)
data = malloc(sizeof(char) * n);
data_cursor = data;
data_size = n;
else
// We compute the position in the buffer as an integer
// to be able to re-apply after realloc(). Because realloc()
// can move the pointer we need this position as an integer.
size_t cursor_pos = data_cursor - data;
tmp = realloc(data, sizeof(char) * data_size + n);
if (tmp == NULL)
goto error;
data = tmp;
data_cursor = data + cursor_pos;
data_size += n;

memcpy(data_cursor, buffer, n);


if (ferror(file))
goto error;

fclose(file);
if (file_size != NULL)
*file_size = data_size;
return data;

error:
if (file != NULL)
fclose(file);
if (data != NULL)
free(data);
return NULL;







share|improve this question













I wrote a function to read the entire content of a file and return a pointer to an allocated bufer containing all the data.



Please could you tell me if there is a better way of doing this ? One solution could be to use stat() to pre-allocate a buffer and do only one read() call but I don't know if it's better, any though ?



#include <stdio.h>
#include <memory.h>

char *file_read(const char *path, size_t *file_size)

FILE *file = fopen(path, "r");
char buffer[FILE_READ_BUFFER_SIZE];
char *tmp = NULL;
char *data = NULL; // The buffer containing the data of the file
char *data_cursor = NULL; // The current position in the data buffer
size_t data_size = 0; // The size of the data buffer
size_t n = 0; // The number of bytes read by fread()

if (file == NULL)
goto error;

while ((n = fread(buffer, sizeof(char), sizeof(buffer), file)) > 0)
if (data == NULL)
data = malloc(sizeof(char) * n);
data_cursor = data;
data_size = n;
else
// We compute the position in the buffer as an integer
// to be able to re-apply after realloc(). Because realloc()
// can move the pointer we need this position as an integer.
size_t cursor_pos = data_cursor - data;
tmp = realloc(data, sizeof(char) * data_size + n);
if (tmp == NULL)
goto error;
data = tmp;
data_cursor = data + cursor_pos;
data_size += n;

memcpy(data_cursor, buffer, n);


if (ferror(file))
goto error;

fclose(file);
if (file_size != NULL)
*file_size = data_size;
return data;

error:
if (file != NULL)
fclose(file);
if (data != NULL)
free(data);
return NULL;









share|improve this question












share|improve this question




share|improve this question








edited Jan 24 at 14:47
























asked Jan 24 at 11:04









Thibaut D.

757




757







  • 1




    Code posted to codereview should compile, it would be great if you could make this a complete file especially could you post the code for error_set_from_errno_ptr() ?
    – Harald Scheirich
    Jan 24 at 13:45










  • It's just a utility function which stores internally the last errrno & strerror() and return NULL. I replaced it with return NULL in my example. Thanks !
    – Thibaut D.
    Jan 24 at 14:48










  • Here you find how to find size of a file using fseek+ftell, and then allocating a buffer that exact size: stackoverflow.com/questions/5957845/… After that use rewind and fread.
    – Andreas
    Jan 24 at 18:46












  • 1




    Code posted to codereview should compile, it would be great if you could make this a complete file especially could you post the code for error_set_from_errno_ptr() ?
    – Harald Scheirich
    Jan 24 at 13:45










  • It's just a utility function which stores internally the last errrno & strerror() and return NULL. I replaced it with return NULL in my example. Thanks !
    – Thibaut D.
    Jan 24 at 14:48










  • Here you find how to find size of a file using fseek+ftell, and then allocating a buffer that exact size: stackoverflow.com/questions/5957845/… After that use rewind and fread.
    – Andreas
    Jan 24 at 18:46







1




1




Code posted to codereview should compile, it would be great if you could make this a complete file especially could you post the code for error_set_from_errno_ptr() ?
– Harald Scheirich
Jan 24 at 13:45




Code posted to codereview should compile, it would be great if you could make this a complete file especially could you post the code for error_set_from_errno_ptr() ?
– Harald Scheirich
Jan 24 at 13:45












It's just a utility function which stores internally the last errrno & strerror() and return NULL. I replaced it with return NULL in my example. Thanks !
– Thibaut D.
Jan 24 at 14:48




It's just a utility function which stores internally the last errrno & strerror() and return NULL. I replaced it with return NULL in my example. Thanks !
– Thibaut D.
Jan 24 at 14:48












Here you find how to find size of a file using fseek+ftell, and then allocating a buffer that exact size: stackoverflow.com/questions/5957845/… After that use rewind and fread.
– Andreas
Jan 24 at 18:46




Here you find how to find size of a file using fseek+ftell, and then allocating a buffer that exact size: stackoverflow.com/questions/5957845/… After that use rewind and fread.
– Andreas
Jan 24 at 18:46










1 Answer
1






active

oldest

votes

















up vote
2
down vote



accepted










  • I recommend to pass a file pointer rather than a path. This will enable the code to work with streams as well. It would also simplify the awkward error handling.


  • Modern c allows, and recommends, to declare variables closer to their use.


  • It is OK to realloc even when data is NULL.


  • sizeof(char) is guaranteed to be 1.



  • Incrementing data_size after memcpy lets you drop data_cursor and cursor_pos, which IMHO obfuscate the code. You'd need to



     memcpy(data + data_size, buffer, n);
    data_size += n;


  • Allocating an array on the stack is usually not recommended. Consider reading directly into data + data_size, and get away without buffer and memcpy.






share|improve this answer





















  • Thanks a lot for those comments, which totally make sense.
    – Thibaut D.
    Jan 24 at 20:10










Your Answer




StackExchange.ifUsing("editor", function ()
return StackExchange.using("mathjaxEditing", function ()
StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix)
StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
);
);
, "mathjax-editing");

StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");

StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "196"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);

else
createEditor();

);

function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
convertImagesToLinks: false,
noModals: false,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);



);








 

draft saved


draft discarded


















StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f185869%2freading-a-file-and-storing-all-the-data-in-a-buffer%23new-answer', 'question_page');

);

Post as a guest






























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes








up vote
2
down vote



accepted










  • I recommend to pass a file pointer rather than a path. This will enable the code to work with streams as well. It would also simplify the awkward error handling.


  • Modern c allows, and recommends, to declare variables closer to their use.


  • It is OK to realloc even when data is NULL.


  • sizeof(char) is guaranteed to be 1.



  • Incrementing data_size after memcpy lets you drop data_cursor and cursor_pos, which IMHO obfuscate the code. You'd need to



     memcpy(data + data_size, buffer, n);
    data_size += n;


  • Allocating an array on the stack is usually not recommended. Consider reading directly into data + data_size, and get away without buffer and memcpy.






share|improve this answer





















  • Thanks a lot for those comments, which totally make sense.
    – Thibaut D.
    Jan 24 at 20:10














up vote
2
down vote



accepted










  • I recommend to pass a file pointer rather than a path. This will enable the code to work with streams as well. It would also simplify the awkward error handling.


  • Modern c allows, and recommends, to declare variables closer to their use.


  • It is OK to realloc even when data is NULL.


  • sizeof(char) is guaranteed to be 1.



  • Incrementing data_size after memcpy lets you drop data_cursor and cursor_pos, which IMHO obfuscate the code. You'd need to



     memcpy(data + data_size, buffer, n);
    data_size += n;


  • Allocating an array on the stack is usually not recommended. Consider reading directly into data + data_size, and get away without buffer and memcpy.






share|improve this answer





















  • Thanks a lot for those comments, which totally make sense.
    – Thibaut D.
    Jan 24 at 20:10












up vote
2
down vote



accepted







up vote
2
down vote



accepted






  • I recommend to pass a file pointer rather than a path. This will enable the code to work with streams as well. It would also simplify the awkward error handling.


  • Modern c allows, and recommends, to declare variables closer to their use.


  • It is OK to realloc even when data is NULL.


  • sizeof(char) is guaranteed to be 1.



  • Incrementing data_size after memcpy lets you drop data_cursor and cursor_pos, which IMHO obfuscate the code. You'd need to



     memcpy(data + data_size, buffer, n);
    data_size += n;


  • Allocating an array on the stack is usually not recommended. Consider reading directly into data + data_size, and get away without buffer and memcpy.






share|improve this answer













  • I recommend to pass a file pointer rather than a path. This will enable the code to work with streams as well. It would also simplify the awkward error handling.


  • Modern c allows, and recommends, to declare variables closer to their use.


  • It is OK to realloc even when data is NULL.


  • sizeof(char) is guaranteed to be 1.



  • Incrementing data_size after memcpy lets you drop data_cursor and cursor_pos, which IMHO obfuscate the code. You'd need to



     memcpy(data + data_size, buffer, n);
    data_size += n;


  • Allocating an array on the stack is usually not recommended. Consider reading directly into data + data_size, and get away without buffer and memcpy.







share|improve this answer













share|improve this answer



share|improve this answer











answered Jan 24 at 19:04









vnp

36.6k12991




36.6k12991











  • Thanks a lot for those comments, which totally make sense.
    – Thibaut D.
    Jan 24 at 20:10
















  • Thanks a lot for those comments, which totally make sense.
    – Thibaut D.
    Jan 24 at 20:10















Thanks a lot for those comments, which totally make sense.
– Thibaut D.
Jan 24 at 20:10




Thanks a lot for those comments, which totally make sense.
– Thibaut D.
Jan 24 at 20:10












 

draft saved


draft discarded


























 


draft saved


draft discarded














StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f185869%2freading-a-file-and-storing-all-the-data-in-a-buffer%23new-answer', 'question_page');

);

Post as a guest













































































Popular posts from this blog

Chat program with C++ and SFML

Function to Return a JSON Like Objects Using VBA Collections and Arrays

Will my employers contract hold up in court?