Thread: homework help wanted: reading a comma seperated file

  1. #1
    Registered User
    Join Date
    Apr 2010
    Posts
    37

    homework help wanted: reading a comma seperated file

    Hello, I'm working on an assignment where we are using file i/o. The goal of the assignment is to read numbers that are seperated by commas in a 2 column x 20 row excel file. I am currently stuck on how to get the numbers out of the file and into the proper sized array. I am ultimately supposed to change the file from seperated by commas to seperated by tab. Here is what I have so far.

    Code:
    #include <iostream>
    #include <fstream>
    #include <string>
    #include <sstream>
    using namespace std;
    
    typedef int* intArrayPtr;
    
    int main () 
    {
      int numberOfColumns = 1; //always at least 1 column
      int numberOfRows = 0;
      int i = 0;
      int i2 = 0;
      string line;
      string getNumbers;
      int numbers[100];
      string checkColumns;
     
      ifstream inStream;
      inStream.open("C201_test_file.csv");
     
      if(inStream.fail())
      {
        cout << "Input file opening failed." << endl;
        exit(1);
      }
    
      getline(inStream, checkColumns);  //check number of columns
      for(i = 0;checkColumns[i] != '\0'; ++i) 
      {	
        if(checkColumns[i] == ',')
        ++numberOfColumns;
      }
    
      inStream.seekg(0, ios::beg); //start over at beginning of file
      i = 0;
    
      while(! inStream.eof()) // check number of rows
      {
        getline(inStream, line);
        ++i;
      }
    
      numberOfRows = i - 1;
    
      inStream.seekg(0, ios::beg);
      inStream.seekg(0, ios::beg);//start over at beginning of file again
      i = 0;
    
      while(! inStream.eof()) // check number of rows
      {
        getline(inStream, getNumbers, ',');
        istringstream buffer(getNumbers);
        buffer >> numbers[i];
        ++i;
      }
    
      intArrayPtr *arrayNumbers = new intArrayPtr[numberOfRows];
      
      for(i = 0; i < numberOfRows; i++) //initialize multidimensional array
        arrayNumbers[i] = new int[numberOfColumns];  
      
      for(i = 0; i < numberOfRows; i++)
        for(i2 = 0; i2 < numberOfColumns; i2++)
          arrayNumbers[i][i2] = numbers[i];
    
      for(i = 0; i < numberOfRows; i++) //display multidimensional array
      {
        for(i2 = 0; i2 < numberOfColumns; i2++)
          cout << arrayNumbers[i][i2] << " ";
        cout << endl;
      }
    	
      inStream.close();
      return 0;
    }
    The problem I am having is that I cannot figure out how to get the numbers out of the file and into an array. The numbers in the excel file are 1-20 in the first column and 10-29 in the second. As it stands now when I debug the program and look at my "numbers[]" array I have 1 and then 11-28. How can I alter what I have in order to take every number in the array and put it into my dynamically allocated array? And I am at a total loss as to how to change the commas to tabs. Any help/advice is appreciated, thanks in advance.
    Last edited by DHart07; 11-17-2010 at 03:48 AM.

  2. #2
    Registered User
    Join Date
    May 2010
    Posts
    4,633
    Is it a requirement to use arrays for this assignment?

    Can you use std::vector instead?

    Please provide a small sample of your input file.

    Jim

  3. #3
    Registered User
    Join Date
    Feb 2003
    Posts
    596
    After reaching eof, you should clear the error flags; otherwise, a standards-compliant compiler (e.g. G++) may fail to read from the input stream any more, so:

    Code:
        inStream.clear();
        inStream.seekg(0, ios::beg);
    You shouldn't be declaring a new istringstream on every iteration of the loop. Declare it once before the loop and simply assign its contents in the loop using the stringstream::str() function.

    Also, don't use ',' as the delimiter for getline; when you do, on the second and subsequent calls to getline you get strings containing newline characters that overlap the ends of the lines in your input file, e.g.: "'2' '4' '\n' '4' '5'", and that's why you are losing half of your numbers. Instead, you can read entire rows from the file into a string and then search through the string, replacing the commas with blanks before loading it into the stringstream. Then extracting numeric values from the stringstream is easy. (Just remember that the stringstream will contain numberOfColumns entries.)

    Easier still, you can simply load each string containing an entire row (including its commas) into the stringstream, then use getline() using the comma delimiter to read from that stringstream into a string (which will now contain a single value each time), and then use atoi() to convert that to an integer.


    You also had an error where you were attempting to assign from the 1-dimensional array to the 2-dimensional array. It should be:
    Code:
                arrayNumbers[i][i2] = numbers[i2+i*numberOfColumns];
    See if you can work out the necessary corrections in the main while loop to load the numbers array.

    By the way, your method of determining the number of rows depends on having an empty line at the end of the file (i.e., the last number must be followed by a newline char).
    Last edited by R.Stiltskin; 11-17-2010 at 10:14 AM.

  4. #4
    Registered User
    Join Date
    Apr 2010
    Posts
    37
    "Easier still, you can simply load each string containing an entire row (including its commas) into the stringstream, then use getline() using the comma delimiter to read from that stringstream into a string (which will now contain a single value each time), and then use atoi() to convert that to an integer."

    This is where I am lost. My misunderstanding is how to pull the numbers out of the file and to be able to use them. I don't quite understand the whole stringstream deal. I know how to get an entire row out, but then I am unsure on how to read from that particular row and take out the numbers themselves and place them into an array so I can use those numbers to place into my dynamic array. I can take a row out, but then how do I use getline() on that particular row?

    And my CSV file is as follows...
    1 10
    2 11
    3 12
    4 13
    5 14
    6 15
    7 16
    8 17
    9 18
    10 19
    11 20
    12 21
    13 22
    14 23
    15 24
    16 25
    17 26
    18 27
    19 28
    20 29
    Last edited by DHart07; 11-17-2010 at 11:12 AM.

  5. #5
    Registered User
    Join Date
    Feb 2003
    Posts
    596
    When you read the line from the file into the string getNumbers, DON'T specify the ',' delimiter. Don't specify any delimiter, so it will use the default '\n' newline character, and therefore getNumbers will contain the entire line, e.g. 1,10

    Then load that string into the stringstream:
    Code:
    buffer.str(getNumbers);
    Now buffer contains 1,10

    Then use getline again, but this time on the stringstream rather than the input file, specifying comma as the delimiter, to read one number at a time from the stringstream into a string, (you can re-use getNumbers for this purpose) e.g:
    Code:
    while( getline( buffer, getNumbers, ',' ) { //...
    and use atoi() to convert that string (which now contains only one of the numbers) into an integer and assign it to the array element.
    Last edited by R.Stiltskin; 11-17-2010 at 11:52 AM.

  6. #6
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,613
    Forunately there is an easier way if you are willing to tolerate some inconvenience.

    If you have a csv file like so,
    1,2,3,
    9,8,7,
    You could read in all the numbers by repeating a statement like

    inStream >> num >> fill;

    where fill is a character and num is a number which is easily replaced by another expression, like a particular matrix location. You will have to check fill in order to make sure it is a comma, and if not, do something about the format error.

    It is important that it really is a csv file, and if your file does not terminate lines with ',' to handle that.

  7. #7
    Registered User
    Join Date
    Apr 2010
    Posts
    37
    Alright, so far that makes sense but I am unsure of the syntax for atoi(). Here is my code for that part.

    Code:
    while(! inStream.eof()) 
    {
      getline(inStream, getNumbers);
      istringstream buffer(getNumbers);
      while( getline( buffer, getNumbers, ',' ))
      {
         numbers[i] = atoi(getNumbers);
         ++i;
       }
    }
    I get an error code, " error C2664: 'atoi' : cannot convert parameter 1 from 'std::string' to 'const char *'" What am I misunderstanding?

  8. #8
    Algorithm Dissector iMalc's Avatar
    Join Date
    Dec 2005
    Location
    New Zealand
    Posts
    6,318
    You can convert from 'std::string' to 'const char *' using the .c_str() member function.
    My homepage
    Advice: Take only as directed - If symptoms persist, please see your debugger

    Linus Torvalds: "But it clearly is the only right way. The fact that everybody else does it some other way only means that they are wrong"

  9. #9
    Registered User
    Join Date
    Apr 2010
    Posts
    37
    Thanks a ton guys, everything works as planned. Thanks for the help and helping me understand everything. I greatly appreciate the time spent. Here is my nearly final code.

    Code:
    #include <iostream>
    #include <fstream>
    #include <string>
    #include <sstream>
    using namespace std;
    
    typedef int* intArrayPtr;
    
    int main () 
    {
      int numberOfColumns = 1;
      int numberOfRows = 0;
      int i = 0;
      int i2 = 0;
      string getNumbers;
      int numbers[100];
      string checkSize;
    
      ifstream inStream; 
      ofstream outStream;
    	
      inStream.open("C201_test_file.csv"); //gather input from file
      if(inStream.fail())
      {
        cout << "Input file opening failed." << endl;
        exit(1);
      }
    
      getline(inStream, checkSize);  //check number of rows
      for(i = 0; checkSize[i] != '\0'; ++i)
      {	
        if(checkSize[i] == ',')
        ++numberOfColumns;
      }
    
      inStream.clear(); //clear any errors from eof()
    
      inStream.seekg(0, ios::beg); //start over at beginning of file
    
      while(! inStream.eof()) // check number of rows
      {
        getline(inStream, checkSize);
        ++numberOfRows;
      }
      numberOfRows -= 1;
    
      inStream.clear(); //clear any errors from eof()
    
      inStream.seekg(0, ios::beg);//start over at beginning of file again
    	
      i = 0; //reset counter
      while(! inStream.eof()) 
      {
        getline(inStream, getNumbers);
        istringstream buffer(getNumbers);
        while( getline( buffer, getNumbers, ',' ))
        {
          istringstream buffer(getNumbers); //convert string to int
          buffer >> numbers[i];
          ++i;
        }
      }
    
      intArrayPtr *arrayNumbers = new intArrayPtr[numberOfRows];
      
      for(i = 0; i < numberOfRows; i++) //initialize multidimensional array
        arrayNumbers[i] = new int[numberOfColumns];  
      
      for(i = 0; i < numberOfRows; i++) //1d array becomes 2d array
        for(i2 = 0; i2 < numberOfColumns; i2++)
          arrayNumbers[i][i2] = numbers[i2+i*numberOfColumns];
    
      cout << "The file contains the following:" << endl;
      for(i = 0; i < numberOfRows; i++) //display multidimensional array
      {
        for(i2 = 0; i2 < numberOfColumns; i2++)
          cout << arrayNumbers[i][i2] << " ";
        cout << endl;
      }
    	
      cout << "Closing file..." << endl;
        inStream.close();
    
      cout << "\nOpening new file to be written..." << endl;
      outStream.open("hart.txt"); //write to this file
      
      if(outStream.fail())
      {
        cout << "Output file opening failed." << endl;
        exit(1);
      }
    
      for(i = 0; i < numberOfRows; i++) //write multidimensional array
      {
        for(i2 = 0; i2 < numberOfColumns; i2++)
          outStream << arrayNumbers[i][i2] << "\t";
        outStream << endl;
      }
    
      cout << "\nThe new file contains the following:" << endl;
      for(i = 0; i < numberOfRows; i++)
      {
        for(i2 = 0; i2 < numberOfColumns; i2++)
          cout << arrayNumbers[i][i2] << "\t";
        cout << endl;
      }
      
      cout << "Closing file..." << endl;
      outStream.close();
      
      return 0;
    }
    Thanks again.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Can you help me about tolower() in file
    By nctar in forum C Programming
    Replies: 7
    Last Post: 05-12-2010, 10:04 AM
  2. opening empty file causes access violation
    By trevordunstan in forum C Programming
    Replies: 10
    Last Post: 10-21-2008, 11:19 PM
  3. sequential file program
    By needhelpbad in forum C Programming
    Replies: 80
    Last Post: 06-08-2008, 01:04 PM
  4. Can we have vector of vector?
    By ketu1 in forum C++ Programming
    Replies: 24
    Last Post: 01-03-2008, 05:02 AM
  5. System
    By drdroid in forum C++ Programming
    Replies: 3
    Last Post: 06-28-2002, 10:12 PM