C++ question regarding how ifstream reads lines and columns - c++

I was reading some old codes of mine and I realize that I don`t know exactly how ifstream works. The following code should just read a file, save its contents into an object and create another file with exactly same data, which is written as:
#include <iostream>
#include <fstream>
using namespace std;
class grade {
public:
float grade1;
float grade2;
float grade3;
};
void read_file(grade data[]){
ifstream myfile("data.txt");
int i=0;
while(myfile >> data[i].grade1){
myfile >> data[i].grade2 >> data[i].grade3;
i=i+1; }
myfile.close();
myfile.clear();
}
void write_file(grade data[]){
ofstream myfile("data_out.txt");
for(int i=0; i<3; i++){
myfile << data[i].grade1 << "\t" << data[i].grade2 << "\t" << data[i].grade3 << endl;
}
myfile.close();
myfile.clear();
}
int main()
{
grade data[3];
read_file(data);
write_file(data);
return 0;
}
With "data.txt" having:
23.5 10.1 11.6
14.3 8.2 9.3
6.5 6.7 5.3
The code works just fine, but I don't get how the ifstream "knows" which line or column it should be at a given moment, since the variable i is not used to control myfile. I am assuming that by default ifstream has two internal variables, one for line and the other for column, that each time a myfile >> xxx command is identified, the column variable is incremented and every time that a loop repeats the line variable is incremented.
It is something like that? Not actually controlling what line or column the code is at a given moment is quite confusing to me.
Lets say, for instance, that in this example I would like to read only the data on the second line and column. Could I access directly it using some explicit expression like 'myfile[1][1] >> xxx'? I guess that getlinecould be used, but since it is used for strings I really don't know.

In read_file() the reading occurs in this loop:
int i=0;
while(myfile >> data[i].grade1){
myfile >> data[i].grade2 >> data[i].grade3;
i=i+1; }
First, this assumes that data[] was already allocated with sufficient number of elements. It's strange since the file was not yet read, so how to know how many records are to be read in advance?
Then, this reading algorithm assumes that the data is in an ordinary text file, in which data elements are space separated:
The myfile >> data[i].grade1 reads the first grade of a new sequence. If it reaches the end of file, the result will be evaluated to false and the loop will end.
Then for every first grade read, the loops reads the next grades of the record: myfile >> data[i].grade2 >> data[i].grade3;
This logic reads in fact one number after the other. The only constraint is that there are one or several spaces between the numbers. The stream therefore doesn't care about columns: it's just the next item to be read.
The following input file would work equally well:
23.5
10.1
11.6
14.3 8.2
9.3 6.5 6.7 5.3
This being said, no need to close and clear the stream at the end of the function: when the function will return, its local objets will be destroyed. This includes the stream object, and the destruction ensures that everything ends right.
Remark: incomplete records are not handled well: if the first grade is present but one of the remaining is missing, the stream will be in an error state, and the grade2 or grade3 elements will be left uninitialized.

Related

How to change input method of this program?

Hello I'm a BME student and don't have so much information on programming. I found a simple program on the internet that I could perfectly use to run my data but it only accepts input by hand. I want to make it automated with the data files I have as it takes so much time entering all the values one by one. Could you please help me to integrate some module to make that possible? I did not want to put the entire program as the code is very long, but the input part is below:
int m;
cout << "Enter the MRI number" << endl;
cin >> m;
cout << "Enter the extensions one by one" << endl;
for (i=1; i<=m; i++)
cin >> a[i];
So the main logic of the program is:
1) Enter the total number of MRI extensions >> 4
2) Enter the MRI extensions >> 12131415 12131411 12131419 12131421
3) Run the algorithm and get the output
And my data file will be like this:
4
12131415
12131411
12131419
12131421
Roughly this is the process, but my data files contain around 70-75 extensions each but not 4 as it is in the example above.
Any kind of help will be much appreciated. Thanks!
p/s if my question somehow violates the rules of asking question, I am really sorry. I read that my question should be including some work done by me, but I really do not know how to handle this.
Basically how it works it is accepting the input stream (cin and cout) you need to do one of two things. Automate it when calling the program (use program which will feed the information for the console), depending on what system you are using for linux something like cat "input file" | your executable. The second possibility is to change the input stream to be file stream. In this case instead of using cin and cout you need to use your own declared file streams exactly the same way.
Here is the example from cplusplus.com:
#include <iostream> // std::cout
#include <fstream> // std::ifstream
int main () {
std::ifstream ifs ("test.txt", std::ifstream::in);
char c = ifs.get();
while (ifs.good()) {
std::cout << c;
c = ifs.get();
}
ifs.close();
return 0;
}
First lines include the input and output stream.
Then this line:
std::ifstream ifs ("test.txt", std::ifstream::in);
constructs the actual stream, rest is the usage of stream.
int m;
std::ifstream myinputfile ("file you want to read", std::ifstream::in);
myinputfile >> m;
for (i=1; i<=m; i++)
myinputfile >> a[i];

Trying to write a class in C++ that only reads in the first column of data and skips to the next line

This may be a very simplistic question, but I have not found any examples to guide me. I am trying to write class in C++ that can read a text file where columns of data (float, char, int, etc...) are separated by spaces. I would like the class to be able to ignore some columns and read in specified columns. For now I am experimenting with one and two column formats and progressing from there. A brief example of a test input file is listed below.
103.816
43.984
2214.5
321.5
615.8
8.186
37.6
My first attempt at writing a code to read in one column of data is trivial and looks like this.
void Read_Columnar_File::Read_File(const std::string& file_name)
{
int i;
std::ifstream inp(file_name,std::ios::in | std::ios::binary);
if(inp.is_open()) {
std::istream_iterator<float> start((inp)), end;
std::vector<float> values(start,end);
for(i=0; i < 7; i++) std::cout << values[i] << std::endl;
}
else std::cout << "Cannot Open " << file_name << std::endl;
inp.close();
}
In my next attempt I am trying to read in only one column of a two column format like the input shown below. The numbers are just made up for this example
103.816 34.18
43.984 21.564
2214.5 18.5
321.5 1.00
615.8 4.28
8.186 1.69
37.6 35.48
I modified the code format slightly to look like the example below. I am using a brief but of pseudocode after the inp >> statement to illustrate that I am trying to get the code to skip to the next line after reading in the first column. my question is "How do I get the code to just read the first column and then skip to the next line where again it just reads the first column of data and make it keep doing this until the end of file?" And thank you in advance for any advice that you can give.
void Read_Columnar_File::Read_File(const std::string& file_name)
{
int i;
float input;
std::vector<float> values;
std::ifstream inp(file_name,std::ios::in | std::ios::binary);
if(inp.is_open()) {
for(i=0; i < 7; i++) {
inp >> input >> \\ - At this point I want the code to skip to the next
\\ line of the input file to only read the first column
\\ of data
values.push_back(input);
}
for(i=0; i < 7; i++) std::cout << values[i] << std::endl;
}
else std::cout << "Cannot Open " << file_name << std::endl;
inp.close();
}
You can use the member function ignore() to discard all the characters until the next line. I would also fix up your code to use a for() loop predicated on the success of the extraction so your code will work for any number of columns, not just 7:
for (float input; inp >> input; values.push_back(input))
{
inp.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
When you want to read only part of a line, and skip the rest of that line, one easy starting point is to:
read the entire line into a string
put the whole string into an istringstream
Parse out the parts you care about
Repeat
As a rule, I generally find this easier to generalize than ones that alternate between reading and ignoring data as it's being read from the file.

C++ reading from file - last element gets read twice [duplicate]

This question already has answers here:
Why is iostream::eof inside a loop condition (i.e. `while (!stream.eof())`) considered wrong?
(5 answers)
Closed 4 years ago.
The following C++ code uses a ifstream object to read integers from a text file (which has one number per line) until it hits EOF. Why does it read the integer on the last line twice? How to fix this?
Code:
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
ifstream iFile("input.txt"); // input.txt has integers, one per line
while (!iFile.eof())
{
int x;
iFile >> x;
cerr << x << endl;
}
return 0;
}
input.txt:
10
20
30
Output:
10
20
30
30
Note: I've skipped all error checking code to keep the code snippet small. The above behaviour is seen on Windows (Visual C++), cygwin (gcc) and Linux (gcc).
Just follow closely the chain of events.
Grab 10
Grab 20
Grab 30
Grab EOF
Look at the second-to-last iteration. You grabbed 30, then carried on to check for EOF. You haven't reached EOF because the EOF mark hasn't been read yet ("binarically" speaking, its conceptual location is just after the 30 line). Therefore you carry on to the next iteration. x is still 30 from previous iteration. Now you read from the stream and you get EOF. x remains 30 and the ios::eofbit is raised. You output to stderr x (which is 30, just like in the previous iteration). Next you check for EOF in the loop condition, and this time you're out of the loop.
Try this:
while (true) {
int x;
iFile >> x;
if( iFile.eof() ) break;
cerr << x << endl;
}
By the way, there is another bug in your code. Did you ever try to run it on an empty file? The behaviour you get is for the exact same reason.
I like this example, which for now, leaves out the check which you could add inside the while block:
ifstream iFile("input.txt"); // input.txt has integers, one per line
int x;
while (iFile >> x)
{
cerr << x << endl;
}
Not sure how safe it is...
There's an alternative approach to this:
#include <iterator>
#include <algorithm>
// ...
copy(istream_iterator<int>(iFile), istream_iterator<int>(),
ostream_iterator<int>(cerr, "\n"));
Without to much modifications of the original code, it could become :
while (!iFile.eof())
{
int x;
iFile >> x;
if (!iFile.eof()) break;
cerr << x << endl;
}
but I prefer the two other solutions above in general.
The EOF pattern needs a prime read to 'bootstrap' the EOF checking process. Consider the empty file will not initially have its EOF set until the first read. The prime read will catch the EOF in this instance and properly skip the loop completely.
What you need to remember here is that you don't get the EOF until the first attempt to read past the available data of the file. Reading the exact amount of data will not flag the EOF.
I should point out if the file was empty your given code would have printed since the EOF will have prevented a value from being set to x on entry into the loop.
0
So add a prime read and move the loop's read to the end:
int x;
iFile >> x; // prime read here
while (!iFile.eof()) {
cerr << x << endl;
iFile >> x;
}
At the end of the last line, you have a new line character, which is not read by >> operator and it is not an end of file.
Please, make an experiment and delete the new line (thelast character in file) - you will not get the duplication.
To have a flexible code and avoid unwanted effects just apply any solution given by other users.
int x;
ifile >> x
while (!iFile.eof())
{
cerr << x << endl;
iFile >> x;
}

Reading text file into C++

I was writing a program which could read inputs directly from a text
file into a C++ file. However, the contents of the file come in
different formats, for example time. The input file looks like this:
Time(1) Price(1)
8:56:18 1250.00
9:00:25 1250.25
9:21:36 1250.50
9:23:32 1249.75
Time(2)
8:55:28
9:02:14
9:20:23
9:21:37
Price(2)
1680.50
1681.00
1680.50
1681.50
My program to read the file is as follows:
int main()
{
string file;
cout << "Enter a file name to read input: ";
cin >> file;
ifstream file_name(file.c_str());
while(!file_name.eof())
{
double input;
file_name >> input;
cout << input << endl;
}
}
But when I executed the program, I get stuck in an infinite loop and
all I see are 0s written on the screen. Is this being caused due the
formatting of the time?
The default behavior of file_name >> input is type safe therefore file_name byte offset pointer never increments for inputs like Time(1) or 8:56:18. You may use string input; instead of double input; to retrieve the values, then later you may check their types by using following standard c library.
#include <cstdlib>
.
.
.
atof()
atoi()
.
Here is the documentation.

Reading from text file until EOF repeats last line [duplicate]

This question already has answers here:
Why is iostream::eof inside a loop condition (i.e. `while (!stream.eof())`) considered wrong?
(5 answers)
Closed 4 years ago.
The following C++ code uses a ifstream object to read integers from a text file (which has one number per line) until it hits EOF. Why does it read the integer on the last line twice? How to fix this?
Code:
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
ifstream iFile("input.txt"); // input.txt has integers, one per line
while (!iFile.eof())
{
int x;
iFile >> x;
cerr << x << endl;
}
return 0;
}
input.txt:
10
20
30
Output:
10
20
30
30
Note: I've skipped all error checking code to keep the code snippet small. The above behaviour is seen on Windows (Visual C++), cygwin (gcc) and Linux (gcc).
Just follow closely the chain of events.
Grab 10
Grab 20
Grab 30
Grab EOF
Look at the second-to-last iteration. You grabbed 30, then carried on to check for EOF. You haven't reached EOF because the EOF mark hasn't been read yet ("binarically" speaking, its conceptual location is just after the 30 line). Therefore you carry on to the next iteration. x is still 30 from previous iteration. Now you read from the stream and you get EOF. x remains 30 and the ios::eofbit is raised. You output to stderr x (which is 30, just like in the previous iteration). Next you check for EOF in the loop condition, and this time you're out of the loop.
Try this:
while (true) {
int x;
iFile >> x;
if( iFile.eof() ) break;
cerr << x << endl;
}
By the way, there is another bug in your code. Did you ever try to run it on an empty file? The behaviour you get is for the exact same reason.
I like this example, which for now, leaves out the check which you could add inside the while block:
ifstream iFile("input.txt"); // input.txt has integers, one per line
int x;
while (iFile >> x)
{
cerr << x << endl;
}
Not sure how safe it is...
There's an alternative approach to this:
#include <iterator>
#include <algorithm>
// ...
copy(istream_iterator<int>(iFile), istream_iterator<int>(),
ostream_iterator<int>(cerr, "\n"));
Without to much modifications of the original code, it could become :
while (!iFile.eof())
{
int x;
iFile >> x;
if (!iFile.eof()) break;
cerr << x << endl;
}
but I prefer the two other solutions above in general.
The EOF pattern needs a prime read to 'bootstrap' the EOF checking process. Consider the empty file will not initially have its EOF set until the first read. The prime read will catch the EOF in this instance and properly skip the loop completely.
What you need to remember here is that you don't get the EOF until the first attempt to read past the available data of the file. Reading the exact amount of data will not flag the EOF.
I should point out if the file was empty your given code would have printed since the EOF will have prevented a value from being set to x on entry into the loop.
0
So add a prime read and move the loop's read to the end:
int x;
iFile >> x; // prime read here
while (!iFile.eof()) {
cerr << x << endl;
iFile >> x;
}
At the end of the last line, you have a new line character, which is not read by >> operator and it is not an end of file.
Please, make an experiment and delete the new line (thelast character in file) - you will not get the duplication.
To have a flexible code and avoid unwanted effects just apply any solution given by other users.
int x;
ifile >> x
while (!iFile.eof())
{
cerr << x << endl;
iFile >> x;
}