domonica domonica - 1 month ago 18
C++ Question

ifstream::read not working?

I am trying to read from a

.csv
file. There are two functions below, one for writing and one for reading.

The file contains a simple table:

date,first,second
1 a one
2 b two
3 c three
4 c four


For some reason, the statement
while(file_stream.read(&c,1));
does not read anything. It stops at the first character and I'm dumbfounded as to why. Any clues?

#include <iostream>
#include <sstream>
#include <fstream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <string>
#include <cstdlib>

using namespace std;

std::string filename;
std::string line_string;
ifstream file_stream;
stringstream ss;
vector< vector<string> > vec;
char c;

void read_file()
{
filename = "test.csv";

cout << filename << endl;

file_stream.open(filename.c_str(),ios::out|ios::binary);
if(file_stream.fail())
{
cout << "File didn't open" << endl;
return;
}

if(file_stream.is_open())
cout << "file opened" << endl;

while(file_stream.read(&c,1)); // this isn't working
{
cout <<"char c is: " << c;
ss << noskipws << c;
}
file_stream.close();
cout << "string is: " << ss.str() << endl;

//get each line
int counter = 0;
vector<string> invec;

while(getline(ss,line_string,'\n'))
{
string header_string;
stringstream header_stream;

header_stream << line_string;

while(getline(header_stream, header_string,','))
{
invec.push_back(header_string);
}
invec.push_back(header_string);

vec.push_back(invec);
invec.clear();
counter++;
}
}

void test_output()
{
for(int i = 0; i < vec.size();i++)
{
for(int in = 0; in < vec[0].size(); in++)
cout << vec[i][in] << " ";

cout << endl;
}
}

int main()
{
read_file();
test_output();
}

Answer

Look very very carefully at the line that is not working:

while(file_stream.read(&c,1));  // this isn't working
{
    cout <<"char c is: " <<  c;
    ss << noskipws << c;
}

The ; character at the end of the while statement does NOT belong! You are running a no-body loop that does not terminate until read() fails, and THEN your code enters the bracketed block to output the last character that was successfully read (if any).

You need to remove that erroneous ; character:

while(file_stream.read(&c,1))  // this works
{
    cout <<"char c is: " <<  c;
    ss << noskipws << c;
}

Now, the real question is - why are you reading the input file character-by-character into a std::stringstream in the first place? You can use std::getline() with the input std::ifstream directly:

#include <iostream>
#include <sstream>
#include <fstream>
#include <vector>
#include <string>

std::vector< std::vector<std::string> > vec;

void read_file()
{
    std::string filename = "test.csv";

    std::cout << filename << std::endl;

    std::ifstream file_stream;
    file_stream.open(filename.c_str(), ios::binary);
    if (!file_stream)
    {
        std::cout << "File didn't open" << std::endl;
        return;
    }

    std::cout << "file opened" << std::endl;

    //get each line
    std::vector<std::string> invec;
    std::string line;
    int counter = 0;

    if (std::getline(file_stream, line))
    {
        std::istringstream iss(line);    
        while (std::getline(iss, line, ','))
            invec.push_back(line);    
        vec.push_back(invec);
        invec.clear();
        ++counter;

        while (std::getline(file_stream, line))
        {
            iss.str(line);
            while (iss >> line)
                invec.push_back(line);    
            vec.push_back(invec);
            invec.clear();
            ++counter;
        }
    }
}

void test_output()
{
    if (!vec.empty())
    {
        for(int in = 0; in < vec[0].size(); ++in)
            std::cout << vec[0][in] << ",";

        std::cout << std::endl;

        for(int i = 1; i < vec.size(); ++i)
        {
            for(int in = 0; in < vec[i].size(); ++in)
                std::cout << vec[i][in] << "   ";

            std::cout << std::endl;
        }
    }
}

int main()
{
    read_file();
    test_output();
}
Comments