55

What is a good approach to read the whole file content in a buffer for C++?

While in plain C I could use fopen(), fseek(), fread() function combination and read the whole file to a buffer, is it still a good idea to use the same for C++? If yes, then how could I use RAII approach while opening, allocating memory for buffer, reading and reading file content to buffer.

Should I create some wrapper class for the buffer, which deallocates memory (allocated for buffer) in it's destructor, and the same wrapper for file handling?

nbro
  • 15,395
  • 32
  • 113
  • 196
vard
  • 2,142
  • 4
  • 30
  • 40

3 Answers3

95

There's no need for wrapper classes for very basic functionality:

std::ifstream file("myfile", std::ios::binary | std::ios::ate);
std::streamsize size = file.tellg();
file.seekg(0, std::ios::beg);

std::vector<char> buffer(size);
if (file.read(buffer.data(), size))
{
    /* worked! */
}
fsenart
  • 5,661
  • 2
  • 35
  • 54
jrok
  • 54,456
  • 9
  • 109
  • 141
  • 9
    Wouldn't uint8_t be better than char? – jiggunjer Jun 30 '15 at 07:52
  • read() doesn't return bool. You need to check file.bad() (or in your case file.good()). – Jamie Sep 06 '16 at 02:06
  • 22
    Jamie - read() returns a reference to the ifstream itself. By using it in a boolean context, you implicitly call operator bool(), which returns the same as !fail() => this code is correct – kshepherd Sep 10 '16 at 15:01
  • 2
    You can't rely on `tellg()` for the file size, AFAICR. – einpoklum Jun 12 '18 at 12:00
  • 5
    if the file is binary, that works. If it's text, then yes you cannot. – Jean-François Fabre Sep 18 '18 at 15:53
  • The constructor of ```std::Vector``` initializes all elements, which is unnecessary. I would expect this solution to be slightly less efficient than the old C equivalent with ```malloc```. – ManuelAtWork Jun 10 '20 at 06:27
  • 2
    [He said you do not use `tellg()` to get the file size.](http://stackoverflow.com/questions/22984956/tellg-function-give-wrong-size-of-file/22986486#22986486) – Константин Ван Dec 13 '20 at 18:55
  • 1
    @КонстантинВан good point, that's right by the language specification, but *in practice* this answer would work fine in Unix. Also works in Windows, since the answer uses the `binary` option. – starriet Aug 27 '22 at 02:08
36

You can access the contents of a file with a input file stream std::ifstream, then you can use std::istreambuf_iterator to iterate over the contents of the ifstream,

std::string
getFileContent(const std::string& path)
{
  std::ifstream file(path);
  std::string content((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());

  return content;
}

In this case im using the iterator to build a new string using the contents of the ifstream, the std::istreambuf_iterator<char>(file) creates an iterator to the begining of the ifstream, and std::istreambuf_iterator<char>() is a default-constructed iterator that indicate the special state "end-of-stream" which you will get when the first iterator reach the end of the contents.

AngelCastillo
  • 2,385
  • 2
  • 18
  • 26
24

Something I have in most of my programs:

/** Read file into string. */
inline std::string slurp (const std::string& path) {
  std::ostringstream buf; 
  std::ifstream input (path.c_str()); 
  buf << input.rdbuf(); 
  return buf.str();
}

Can be placed in a header.
I think I have found it here: https://stackoverflow.com/a/116220/257568

AntonioCS
  • 8,335
  • 18
  • 63
  • 92
ArtemGr
  • 11,684
  • 3
  • 52
  • 85