0

What can I do when my file s2.txt looks like

ID 1 (string) 
22 30 30 4 2 4 5 7 5 3 ......................................(a few lines   
of numbers) 
ID 2
30 4 2 1 2 ................................. (other lines of numbers)

I want save numbers to vector but it doesn't work:

void readFromFile (){
      ifstream file("s2.txt");
      if( file.good() == true )
          cout << "open" << endl;
      else
          cout << "denied" << endl;

      int m=0;
      while(!file.eof()) {
        string ID;
        int qual;
        vector <int> quality;
        getline(file,ID);
        while (file>>qual) {
          quality.push_back(qual);
          cout<<quality[m]<<endl;
          m++;
        }
      }
      file.close();
    }
}

main () {
readFromFile();
}

When I click "Run" only one string of numbers is save to a vector (for ID1).

PS. Reading ID is not important.

iBug
  • 30,581
  • 7
  • 64
  • 105
Astmara
  • 11
  • 1
  • 1
    You are closing the file in each iteration. – mdatsev Feb 05 '18 at 10:57
  • @mdatsev No, that only seemed so. After having formatted the code, you see, the sample is incomplete, but `file.close()` is outside of `while` loop. – Scheff's Cat Feb 05 '18 at 10:59
  • Btw. you even don't need `m`. The last element of a `std::vector` may be accessed with `std::vector::back()` - in your case `quality.back()` instead of `quality[m]`. Additionally, you don't need to track the length of a `std::vector` as this is also built-in - `std::vector::size()`. – Scheff's Cat Feb 05 '18 at 11:06
  • 1
    [Why is iostream::eof inside a loop condition considered wrong?](https://stackoverflow.com/questions/5605125/why-is-iostreameof-inside-a-loop-condition-considered-wrong) –  Feb 05 '18 at 11:06
  • `while (file>>qual)` will fail once you complete a data line and it moves to the next, trying to make a valid integer from the characters `ID`, and failing miserably. From there, the stream state is set to bad, and both loops fail. Thus, one line starting with ID skipped, one line of integers, then failure, and eventually termination. May want to rethink this and consider per-line-processing of both skipped lines and data lines. And take to heart the link from manni. It's important. – WhozCraig Feb 05 '18 at 11:27

2 Answers2

3

You should read each line to a string. Then check for "ID" string. If "ID" string is found at position 0 of a line then read that line as a ID line, if not, read that line as a line of integer numbers.

Linh Dao
  • 905
  • 1
  • 13
  • 25
1

As suggested in the answer of Linh Dao, I made a respective sample code:

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

void readFromFile(std::istream &in)
{
  if (!in.good()) {
    std::cerr << "ERROR!" << std::endl;
  }
  std::string buffer;
  std::vector<int> quality;
  while (std::getline(in, buffer)) {
    if (buffer.size() >= 2 && buffer.compare(0, 2, "ID") == 0) {
      std::cout << buffer << std::endl;
      quality.clear(); // reset quality vector
    } else {
      // read numbers
      std::istringstream in(buffer); int qual;
      while (in >> qual) {
        quality.push_back(qual);
        std::cout << quality.back() << std::endl;
      }
    }
  }
}

int main(void)
{
#if 0 // in OP
  { std::ifstream fIn("s2.txt");
    readFromFile(fIn);
  } // fIn goes out of scope -> file is closed
#else // instead
  readFromFile(std::cin);
#endif // 0
  return 0;
}

Input:

ID 1 (string) 
22 30 30 4 2 4 5 7 5 3
22 30 30 4 2 4 5 7 5 3
ID 2
30 4 2 1 2

Output:

ID 1 (string) 
22
30
30
4
2
4
5
7
5
3
22
30
30
4
2
4
5
7
5
3
ID 2
30
4
2
1
2

Life demo on ideone.

Note:

The input stream is read line by line (into std::string buffer). The further processing depends on whether the input buffer contents starts with ID. If not, the buffer is used with std::istringstream to extract int numbers.


If I understood the comment right, the questioner intended to output the whole collected quality vector in each iteration. Hence, I modified the first sample and added an output operator<<() for std::vector<int>:

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

// a stream operator for vector<int> ouput
std::ostream& operator<<(std::ostream &out, const std::vector<int> &values)
{
  const char *sep = "";
  for (int value : values) {
    out << sep << value; sep = " ";
  }
  return out;
}

void readFromFile(std::istream &in)
{
  if (!in.good()) {
    std::cerr << "ERROR!" << std::endl;
  }
  std::string buffer;
  std::vector<int> quality;
  while (std::getline(in, buffer)) {
    if (buffer.size() >= 2 && buffer.compare(0, 2, "ID") == 0) {
      std::cout << buffer << std::endl;
      quality.clear(); // reset quality vector
    } else {
      // read numbers
      std::istringstream in(buffer); int qual;
      while (in >> qual) {
        quality.push_back(qual);
        std::cout << quality << std::endl;
      }
    }
  }
}

int main(void)
{
#if 0 // in OP
  { std::ifstream fIn("s2.txt");
    readFromFile(fIn);
  } // fIn goes out of scope -> file is closed
#else // instead
  readFromFile(std::cin);
#endif // 0
  return 0;
}

Input: the same like above

Output:

ID 1 (string) 
22
22 30
22 30 30
22 30 30 4
22 30 30 4 2
22 30 30 4 2 4
22 30 30 4 2 4 5
22 30 30 4 2 4 5 7
22 30 30 4 2 4 5 7 5
22 30 30 4 2 4 5 7 5 3
22 30 30 4 2 4 5 7 5 3 22
22 30 30 4 2 4 5 7 5 3 22 30
22 30 30 4 2 4 5 7 5 3 22 30 30
22 30 30 4 2 4 5 7 5 3 22 30 30 4
22 30 30 4 2 4 5 7 5 3 22 30 30 4 2
22 30 30 4 2 4 5 7 5 3 22 30 30 4 2 4
22 30 30 4 2 4 5 7 5 3 22 30 30 4 2 4 5
22 30 30 4 2 4 5 7 5 3 22 30 30 4 2 4 5 7
22 30 30 4 2 4 5 7 5 3 22 30 30 4 2 4 5 7 5
22 30 30 4 2 4 5 7 5 3 22 30 30 4 2 4 5 7 5 3
ID 2
30
30 4
30 4 2
30 4 2 1
30 4 2 1 2

Life demo on ideone.

Scheff's Cat
  • 16,517
  • 5
  • 25
  • 45