4

I have a .csv file that has 3 rows and 5 columns with values of 0,1,2,3,50, or 100. I saved it from an excel sheet to a .csv file. I am trying to use C++ to read in a .csv file and output the first two column values in the .csv file into a text file based on the last three column values. I am assuming the .csv file looks like

1,1,value,value,value

1,2,value,value,value

1,3,value,value,value

But I couldn't find a whole lot of documentation on the format of .csv files.

I looked at Reading Values from fields in a .csv file? and used some of the code from there.

Here is my code:

#include <iostream>

#include <fstream>

using namespace std;

char separator;
int test_var;

struct Spaxel {
  int array1;
  int array2;
  int red;
  int blue_o2;
  int blue_o3;
};

Spaxel whole_list [3];

int main()
{
    // Reading in the file
    ifstream myfile("sample.csv");
    Spaxel data;
    int n = 0;
    cout << data.array1<< endl;
    myfile >> data.array1; // using as a test to see if it is working
    cout << data.array1<< endl;
    while (myfile >> data.array1)
    {
        // Storing the 5 variable and getting rid of commas
        cout<<"here?"<< endl;
        // Skip the separator, e.g. comma (',')
        myfile >> separator;

        // Read in next value.
        myfile >> data.array2;

        // Skip the separator
        myfile >> separator;

        // Read in next value.
        myfile >> data.red;

        // Skip the separator, e.g. comma (',')
        myfile >> separator;

        // Read in next value.
        myfile >> data.blue_o2;

        // Skip the separator
        myfile >> separator;

        // Read in next value.
        myfile >> data.blue_o3;

        // Ignore the newline, as it is still in the buffer.
        myfile.ignore(10000, '\n');

        // Storing values in an array to be printed out later into another file
        whole_list[n] = data;
        cout << whole_list[n].red << endl;
        n++;

        }
    myfile.close();

    // Putting contents of whole_list in an output file
    //whole_list[0].red = whole_list[0].array1 = whole_list[0].array2 = 1; this was a test     and it didn't work
    ofstream output("sample_out.txt");
    for (int n=0; n<3; n++) {
        if (whole_list[n].red == 1)
            output << whole_list[n].array1 <<","<< whole_list[n].array2<< endl;
    }
    return 0;
}

When I run it in Xcode it prints three 0's (from the cout << data.array1<< endl; and cout << data.array1<< endl; in the beginning of the main() and from the return 0) but does not output any file. Apparently the .csv file isn't getting read in correctly and the output file is not getting written correctly. Any suggestions?

Thanks for your time!

Community
  • 1
  • 1

2 Answers2

4

There are a couple of problem areas in the code you presented:

  • Hard coded filename. Running your program in a directory that doesn't have "sample.csv" could cause the ifstream failure you're seeing.
  • No checking whether myfile opened successfully or not.
  • Loop can access an out-of-bound index in whole_list if "sample.csv" has more lines.

The refactored code below, while not completely foolproof, corrects many of the issues mentioned. It should get you most of the way there.

#include <iostream>
#include <vector>
#include <fstream>
#include <sstream>
using namespace std;


struct Spaxel
{
  int array1;
  int array2;
  int red;
  int blue_o2;
  int blue_o3;
};

ostream& operator << (ostream &os, const Spaxel &rhs)
{
  os << rhs.array1
     << ','
     << rhs.array2
     << ','
     << rhs.red
     << ','
     << rhs.blue_o2
     << ','
     << rhs.blue_o3;

  return os;
}

istream& operator >> (istream &is, Spaxel &rhs)
{
  char delim;
  is >> rhs.array1
     >> delim
     >> rhs.array2
     >> delim
     >> rhs.red
     >> delim
     >> rhs.blue_o2
     >> delim
     >> rhs.blue_o3;

  return is;
}


int main(int argc, const char *argv[])
{
    if(argc < 2)
    {
      cout << "Usage: " << argv[0] << " filename\n";
      return 1;
    }

    const char *infilename = argv[argc - 1];
    // Reading in the file
    ifstream myfile(infilename);
    if(!myfile) 
    {
      cerr << "Couldn't open file " << infilename;
      return 1;
    }

    vector<Spaxel> whole_list;
    string line;
    while( getline(myfile, line) )
    {
      Spaxel data;
      stringstream linestr (line);
      linestr >> data;
      whole_list.push_back(data);

      cout << data << '\n';
    }
}

Edit: Just to help clarify some things from the comment.

As you know main is the entry point of your program so it isn't something called by your own code. The extra optional parameters int argc, const char *argv[], is how options and parameters get passed in when you run your program with arguments. First parameter argc indicates how many arguments were passed in. The second argv is an array of char * with each element being the argument passed. The first argument argv[0] is your program name and so argc is always >= 1.

Say you execute your sample program from the shell:

./sample sample.csv

then argc and argv will have the following:

argc = 2;
argv[0] = "sample"
argv[1] = "sample.csv"

So const char *infilename = argv[argc - 1]; gets the last argument passed in which should be the filename to read in.

greatwolf
  • 20,287
  • 13
  • 71
  • 105
  • Wow I was way off. Thanks so much for helping me in the correct direction. Another question. I haven't ever used arguments for the main loop. Do I need to call the main loop? I think I do because otherwise the filename won't get put in… But when I tried calling it, Xcode was angry. And also what is the argc important for? I don't understand the line const char *infilename = argv[argc - 1]; why are you setting a pointer array = to an element of an array? are you setting it to the memory address? – astronomer_in_training Jun 13 '13 at 13:14
  • @astronomer_in_training I've added an edit to help clear some things up. – greatwolf Jun 13 '13 at 19:04
0

Sorry i am not doing it within struct but i hope you will got it and resolve your problem.

char separator;
    int value1;
    int value2;
    int value3;
    while (myfile >> value1)
    {
        // Skip the separator, e.g. comma (',')
        myfile >> separator;

        // Read in next value.
        myfile >> value2;

        // Skip the separator, e.g. comma (',')
        myfile >> separator;

        // Read in next value.
        myfile >> value3;

        // Ignore the newline, as it is still in the buffer.
        myfile.ignore(10000, '\n');

    }

The above code fragment is not robust but demonstrates the concept of reading from a file, skipping non-numeric separators and processing the end of the line. The code is optimized either.

Shahzaib Chadhar
  • 178
  • 1
  • 10