Navigation



13.6 — Basic file I/O

File I/O in C++ works very similarly to normal I/O (with a few minor added complexities). There are 3 basic file I/O classes in C++: ifstream (derived from istream), ofstream (derived from ostream), and fstream (derived from iostream). These classes do file input, output, and input/output respectively. To use the file I/O classes, you will need to include the fstream.h header.

Unlike the cout, cin, cerr, and clog streams, which are already ready for use, file streams have to be explicitly set up by the programmer. However, this is extremely simple: to open a file for reading and/or writing, simply instantiate an object of the appropriate file I/O class, with the name of the file as a parameter. Then use the insertion (<<) or extraction (>>) operator to read/write to the file. Once you are done, there are several ways to close a file: explicitly call the close() function, or just let the file I/O variable go out of scope (the file I/O class destructor will close the file for you).

File output

To do file output in the following example, we’re going to use the ofstream class. This is extremely straighforward:

#include <fstream>
#include <iostream>

int main()
{
    using namespace std;

    // ofstream is used for writing files
    // We'll make a file called Sample.dat
    ofstream outf("Sample.dat");

    // If we couldn't open the output file stream for writing
    if (!outf)
    {
        // Print an error and exit
        cerr << "Uh oh, Sample.dat could not be opened for writing!" << endl;
        exit(1);
    }

    // We'll write two lines into this file
    outf << "This is line 1" << endl;
    outf << "This is line 2" << endl;

    return 0;

    // When outf goes out of scope, the ofstream
    // destructor will close the file
}

If you look in your project directory, you should see a file called Sample.dat. If you open it with a text editor, you will see that it indeed contains two lines we wrote to the file.

Note that it is also possible to use the put() function to write a single character to the file.

File input

Now, we’ll take the file we wrote in the last example and read it back in from disk. Note that ifstream returns a 0 if we’ve reached the end of the file (EOF). We’ll use this fact to determine how much to read.

#include <fstream>
#include <iostream>
#include <string>

int main()
{
    using namespace std;

    // ifstream is used for reading files
    // We'll read from a file called Sample.dat
    ifstream inf("Sample.dat");

    // If we couldn't open the output file stream for reading
    if (!inf)
    {
        // Print an error and exit
        cerr << "Uh oh, Sample.dat could not be opened for reading!" << endl;
        exit(1);
    }

    // While there's still stuff left to read
    while (inf)
    {
        // read stuff from the file into a string and print it
        std::string strInput;
        inf >> strInput;
        cout << strInput << endl;
    }

    return 0;

    // When inf goes out of scope, the ifstream
    // destructor will close the file
}

This produces the result:

This
is
line
1
This
is
line
2

Hmmm, that wasn’t quite what we wanted. Remember that the extraction operator deals with “formatted output”, and breaks on whitespace. In order to read in entire lines, we’ll have to use the getline() function.

#include <fstream>
#include <iostream>
#include <string>

int main()
{
    using namespace std;

    // ifstream is used for reading files
    // We'll read from a file called Sample.dat
    ifstream inf("Sample.dat");

    // If we couldn't open the input file stream for reading
    if (!inf)
    {
        // Print an error and exit
        cerr << "Uh oh, Sample.dat could not be opened for reading!" << endl;
        exit(1);
    }

    // While there's still stuff left to read
    while (inf)
    {
        // read stuff from the file into a string and print it
        std::string strInput;
        getline(inf, strInput);
        cout << strInput << endl;
    }

    return 0;

    // When inf goes out of scope, the ifstream
    // destructor will close the file
}

This produces the result:

This is line 1
This is line 2

Buffered output

Output in C++ may be buffered. This means that anything that is output to a file stream may not be written to disk immediately. Instead, several output operations may be batched and handled together. This is done primarily for performance reasons. When a buffer is written to disk, this is called flushing the buffer. One way to cause the buffer to be flushed is to close the file — the contents of the buffer will be flushed to disk, and then the file will be closed.

Buffering is usually not a problem, but in certain circumstance it can cause complications for the unwary. The main culprit in this case is when there is data in the buffer, and then program terminates immediately (either by crashing, or by calling exit()). In these cases, the destructors for the file stream classes are not executed, which means the files are never closed, which means the buffers are never flushed. In this case, the data in the buffer is not written to disk, and is lost forever. This is why it is always a good idea to explicitly close any open files before calling exit().

It is possible to flush the buffer manually using the ostream flush() function. Calling flush() can be useful to ensure the contents of the buffer are written to disk immediately, just in case the program crashes.

File modes

What happens if we try to write to a file that already exists? Running the output example again shows that the original file is completely overwritten each time the program is run. What if, instead, we wanted to append some more data to the end of the file? It turns out that the file stream constructors take an optional second parameter that allows you to specify information about how the file should be opened. This parameter is called mode, and the valid flags that it accepts live in the Ios class.

Ios file mode Meaning
app Opens the file in append mode
ate Seeks to the end of the file before reading/writing
binary Opens the file in binary mode (instead of text mode)
in Opens the file in read mode (default for ifstream)
nocreate Opens the file only if it already exists
noreplace Opens the file only if it does not already exist
out Opens the file in write mode (default for ofstream)
trunc Erases the file if it already exists

It is possible to specify multiple flags by bitwise ORing them together (using the | operator). Note that ios::in and ios::out are already defaults for the ifstream and ofstream classes respectively. If you opt to use fstream (which can do both input and output), you explicitly have to pass in ios::in and/or ios::out depending on which mode you’d like to use.

Let’s write a program that appends two more lines to the Sample.dat file we previously created:

int main()
{
    using namespace std;

    // We'll pass the ios:app flag to tell the ofstream to append
    // rather than rewrite the file.  We do not need to pass in ios::out
    // because ofstream defaults to ios::out
    ofstream outf("Sample.dat", ios::app);

    // If we couldn't open the output file stream for writing
    if (!outf)
    {
        // Print an error and exit
        cerr << "Uh oh, Sample.dat could not be opened for writing!" << endl;
        exit(1);
    }

    outf << "This is line 3" << endl;
    outf << "This is line 4" << endl;

	return 0;

    // When outf goes out of scope, the ofstream
    // destructor will close the file
}

Now if we take a look at Sample.dat (using one of the above sample programs that prints its contents, or loading it in a text editor), we will see the following:

This is line 1
This is line 2
This is line 3
This is line 4

Explicitly opening files using open()

Just like it is possible to explicitly close a file stream using close(), it’s also possible to explicitly open a file stream using open(). open() works just like the file stream constructors — it takes a file name and an optional file mode.

For example:

ofstream outf("Sample.dat");
outf << "This is line 1" << endl;
outf << "This is line 2" << endl;
outf.close(); // explicitly close the file

// Oops, we forgot something
outf.open("Sample.dat", ios::app);
outf << "This is line 3" << endl;
outf.close();
13.7 — Random file I/O
Index
13.5 — Stream states and input validation

24 comments to 13.6 — Basic file I/O

  • [...] 2007 Prev/Next Posts « 13.6 — Basic file I/O | Home | 14.1 — Function templates » Friday, April 4th, 2008 at 10:04 [...]

  • Very nice… I can do a lot with this stuff. :)
    By the way Alex :
    Is there any way to change where to save the files that we make with ofstream? for example- I want to save my Sample.dat to desktop.
    Thanks

    • I believe instead of specifying just a filename, you can specify a path and a filename. I’m not sure which directory corresponds to the windows desktop, but there is one somewhere on your hard drive…

      • alex

        I tried adding the complete path and filename, but it still outputs the file in the projects folder.
        Is there a way to actually output the file where you want? It can’t be that difficult…
        Thanx

  • Mountaingod

    I don’t know if anybody checks these for comments, but outputting to text files doesn’t work for me in Visual C++ 2008 :(

    I’ve copy-pasted your output example exactly. The program compiles & runs, but no text file results. What’s happening?

    • I do read all the comments (eventually). I don’t know why it wouldn’t be outputting a file. Perhaps you don’t have permission to create files in the output directory? Seems unlikely though. You might do a google search on ofstream() and see if you can find reasons that it might fail. I can’t think of any other obvious reasons.

    • Chandrakant

      if you given complete file path using single slash separator like “c:\test\abc.txt” try with double slash separator like “c:\\test\\abc.txt”

  • Coderdude

    Hmm… I’m wondering if you can make the program so that the user can write to the file? Like, something with cin. Is it possible? It probably is, and has an easy explanation, but I just want to know if it is possible, and how to write the program to do this if it is possible. Thanks!!

    • tylerfb11

      It sure is possible! You can outf a varible just like you do with cout:

      int main()
      {
          using namespace std;
      
          int nMyFavNum;
          char nMyFavLet;
      
          cout <> nMyFavNum;
          cout <> nMyFavLet;
      
          ofstream outf("MyFile.txt");
      
          outf << "My favorite number is: ";
          outf << nMyFavNum << endl;
          outf << "My favorite letter is: ";
          outf << nMyFavLet << endl;
      
          cout << "Thank-you!" << endl;
          system("pause");
      
        return 0;
      }
      

      -Tyler

  • chrys

    For those that get an “error: ‘exit’ was not declared in this scope” they have to include

  • Sakthi

    Hello Alex,
    In the first program in this page, why do we need to include both fstream and iostream header files?
    You have already mentioned that fstream class is derived from iostream class. Then isn’t it enough if we include only fstream ?

  • el_ivan

    Learncpp has the best c++ tutorial I’ve seen so far, thank you very much for this set of tutorials.

    I’ve learned so much on the past 3 weeks thanks to this website.

  • Onix_GCI

    First paragraph says that the header is fstream.h, it is probably should be just fstream.

  • 1krishna23

    hello,

    Is it possible to pass an object data/parameter/member to FILE,if it possible please write a small program that a class contain one char and int variable,and how to read the object from FILE.

  • GS

    I wanted to create CPP application which will access data from MySQL database, i have now idea from where to start, looking for guidance ?

    i hope i have placed my question at right place

  • AlwaysLearning

    This works fine for me, but this while loop adds an extra new line character when outputting both to the console and to a file. What would be the most efficient way of avoiding this issue?

  • thunder boldt

    can any one help me write a code using cstirings and arrays maybe for-loops help please i’m a sophomore in high-school

  • boyydz

    Any idea why I get a stack overflow exception while writing to ofstream?

  • kekie

    error: ‘nocreate’ is not a member of ‘std::ios {aka std::basic_ios}’|

  • I am trying to prepare a simple converter that reads data from a file and then rearranges the data followed by its writing work in a different file.

    I have written the code in CODE::BLOCKS. It is compiled without any error. However, while running it fails and gives message that the program has stopped working.

    The code written is as below:
    /*dump2VTKconverter*/
    #include
    #include
    #include “stdio.h”

    /*************************For reading data from files*************************************/
    #include “assert.h”
    #include “stdio.h”
    #include
    #include
    /*****************************************************************************************/

    using namespace std;

    /* ———————Function to jump to a specific line of file————————- */
    std::ifstream& GotoLine(std::ifstream& myfile, unsigned int num)
    {
    myfile.seekg(std::ios::beg);
    for(int i=0; i < num – 1; ++i)
    {
    myfile.ignore(std::numeric_limits::max(),’\n’);
    }
    return myfile;
    }

    /* ————————–Function to write an array to a file—————————- */
    std::fstream& writefile(std::fstream& file, int nparticles, int ntimestep, double *array, int array_length, int array_type)
    {
    if(file.is_open())
    {
    file<<"\n";
    if(array_type == 1)
    {
    file<<ntimestep;
    file<<"\t \t";
    file<<nparticles;
    file<<"\t \t";
    }
    for(int i = 0; i < array_length; i++)
    {
    file<<array[i];
    file<<"\t";
    }
    }
    }
    /*———————————————————————————————*/

    int main()
    {
    int NoOfPropertiesInDumpFiles=0; int TimeStepLineNo=0; int NoOfAtomsLineNo=0; int FirstDataLineNo=0;

    cout <> NoOfPropertiesInDumpFiles;
    cout <> TimeStepLineNo;
    cout <> NoOfAtomsLineNo;
    cout <> FirstDataLineNo;

    int TimeStep=0; int NoOfAtoms=0; int LineNo=0;

    int *ATOM_ID; int *ATOM_TYPE01; int *ATOM_TYPE02; double *X; double *Y; double *Z; double *IX; double *IY; double *IZ;
    double *VX; double *VY; double *VZ; double *FX; double *FY; double *FZ; double *OMEGAX; double *OMEGAY; double *OMEGAZ;
    double *Radius;

    for(int i=1;10;i++)
    {
    ifstream dumpFile(“dumpfile”);
    //dumpFile.open(“dumpfile”, std::ios::in::out);

    if(ATOM_ID) delete[] ATOM_ID; if(ATOM_TYPE01) delete[] ATOM_TYPE01; if(ATOM_TYPE02) delete[] ATOM_TYPE02; if(X) delete[] X; if(Y) delete[] Y; if(Z) delete[] Z;
    if(IX) delete[] IX; if(IY) delete[] IY; if(IZ) delete[] IZ; if(VX) delete[] VX; if(VY) delete[] VY; if(VZ) delete[] VZ;
    if(FX) delete[] FX; if(FY) delete[] FY; if(FZ) delete[] FZ; if(OMEGAX) delete[] OMEGAX; if(OMEGAY) delete[] OMEGAY; if(OMEGAZ) delete[] OMEGAZ; if(Radius) delete[] Radius;

    ATOM_ID=new int[NoOfAtoms]; ATOM_TYPE01=new int[NoOfAtoms]; ATOM_TYPE02=new int[NoOfAtoms]; X=new double[NoOfAtoms]; Y=new double[NoOfAtoms]; Z=new double[NoOfAtoms];
    IX=new double[NoOfAtoms]; IY=new double[NoOfAtoms]; IZ=new double[NoOfAtoms]; VX=new double[NoOfAtoms]; VY=new double[NoOfAtoms]; VZ=new double[NoOfAtoms];
    FX=new double[NoOfAtoms]; FY=new double[NoOfAtoms]; FZ=new double[NoOfAtoms]; OMEGAX=new double[NoOfAtoms]; OMEGAY=new double[NoOfAtoms]; OMEGAZ=new double[NoOfAtoms]; Radius=new double[NoOfAtoms];

    GotoLine(dumpFile,TimeStepLineNo);
    dumpFile>>TimeStep;
    GotoLine(dumpFile,NoOfAtomsLineNo);
    dumpFile>>NoOfAtoms;

    LineNo = FirstDataLineNo; int Current_ATOM_No=0;
    while(LineNo >ATOM_ID[Current_ATOM_No]; dumpFile>>ATOM_TYPE01[Current_ATOM_No]; dumpFile>>ATOM_TYPE02[Current_ATOM_No]; dumpFile>>X[Current_ATOM_No]; dumpFile>>Y[Current_ATOM_No]; dumpFile>>Z[Current_ATOM_No];
    dumpFile>>IX[Current_ATOM_No]; dumpFile>>IY[Current_ATOM_No]; dumpFile>>IZ[Current_ATOM_No]; dumpFile>>VX[Current_ATOM_No]; dumpFile>>VY[Current_ATOM_No]; dumpFile>>VZ[Current_ATOM_No];
    dumpFile>>FX[Current_ATOM_No]; dumpFile>>FY[Current_ATOM_No]; dumpFile>>FZ[Current_ATOM_No]; dumpFile>>OMEGAX[Current_ATOM_No]; dumpFile>>OMEGAY[Current_ATOM_No]; dumpFile>>OMEGAZ[Current_ATOM_No]; dumpFile>>Radius[Current_ATOM_No];
    LineNo++; Current_ATOM_No++;
    }
    // dumpFile.close();
    ofstream vtkFile(“vtkfile”);
    vtkFile << "# vtk DataFile Version 2.0" << endl;
    vtkFile << "Generated by Rahul K Soni" << endl;
    vtkFile << "ASCII" << endl;
    vtkFile << "DATASET POLYDATA" << endl;
    vtkFile << "POINTS " << NoOfAtoms << " float" << endl;
    for(int i=0; NoOfAtoms; i++)
    {
    vtkFile << X[i] << " " << Y[i] << " " << Z[i] << endl;
    }
    vtkFile << "VERTICES " << NoOfAtoms << " " << NoOfAtoms*2.0 << endl;
    for(int i=0; NoOfAtoms; i++)
    {
    vtkFile << 1 << " " << i << endl;
    }
    vtkFile << "POINT_DATA " << NoOfAtoms << endl;
    vtkFile << "VECTORS i float" << endl;
    for(int i=0; NoOfAtoms; i++)
    {
    vtkFile << IX[i] << " " << IY[i] << " " << IZ[i] << endl;
    }
    vtkFile << "VECTORS f float" << endl;
    for(int i=0; NoOfAtoms; i++)
    {
    vtkFile << FX[i] << " " << FY[i] << " " << FZ[i] << endl;
    }
    vtkFile << "VECTORS v float" << endl;
    for(int i=0; NoOfAtoms; i++)
    {
    vtkFile << VX[i] << " " << VY[i] << " " << VZ[i] << endl;
    }
    vtkFile << "SCALARS omegax float 1" << endl;
    vtkFile << "LOOKUP_TABLE default" << endl;
    for(int i=0; NoOfAtoms; i++)
    {
    vtkFile << OMEGAX[i] << endl;
    }
    vtkFile << "SCALARS omegay float 1" << endl;
    vtkFile << "LOOKUP_TABLE default" << endl;
    for(int i=0; NoOfAtoms; i++)
    {
    vtkFile << OMEGAY[i] << endl;
    }
    vtkFile << "SCALARS omegaz float 1" << endl;
    vtkFile << "LOOKUP_TABLE default" << endl;
    for(int i=0; NoOfAtoms; i++)
    {
    vtkFile << OMEGAZ[i] << endl;
    }
    vtkFile << "SCALARS radius float 1" << endl;
    vtkFile << "LOOKUP_TABLE default" << endl;
    for(int i=0; NoOfAtoms; i++)
    {
    vtkFile << Radius[i] << endl;
    }
    vtkFile << "SCALARS type float 1" << endl;
    vtkFile << "LOOKUP_TABLE default" << endl;
    for(int i=0; NoOfAtoms; i++)
    {
    vtkFile << ATOM_TYPE01[i] << endl;
    }
    vtkFile << "SCALARS id float 1" << endl;
    vtkFile << "LOOKUP_TABLE default" << endl;
    for(int i=0; NoOfAtoms; i++)
    {
    vtkFile << ATOM_ID[i] << endl;
    }
    }

    return 0;
    }

You must be logged in to post a comment.