This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 10 years ago.
I wrote a program that reads to one file, writes to another and prints to the screen. In other words, it is supposed to do three things (i.e. read, write and print).
The program is also supposed to count the number of records in a file named "Chap_11_employee_data.txt". It is just displaying the following, however.
**Total Records 0**
The End
When it writes to a file, it also displays weird numbers such as -858993460. I have tried almost everything, which led me to register an account here. My code is listed below as well as the file I am trying to read from and the file I am trying to write to.
Thank you very much for your guy's time.
Code:
#include <iostream>
#include <fstream>
#include <iomanip>
using std::cin;
using std::cout;
using std::endl;
using std::setw;
using std::ios;
using std::ifstream;
using std::ofstream;
const int EMPLOYEES = 20;
const int MAX = 21;
int ReadData( ifstream &inFile, ofstream &outFile, char name[][MAX], int age[] );
void WriteOutputFile( ofstream &outFile, char name[ ][MAX], int age[ ], int counter );
void PrintTotalsAndSummary( ofstream &out, int totalRecords );
int main()
{
char name[EMPLOYEES][MAX];
int age[EMPLOYEES];
int record_counter(0);
ifstream inFile;
ofstream outFile( "Chap_11_Report.txt" );
inFile.open( "Chap_11_employee_data.txt" );
if ( inFile.is_open() )
{
record_counter = ReadData( inFile, outFile, name, age );
inFile.close();
if( outFile.is_open() )
{
WriteOutputFile( outFile, name, age, record_counter );
PrintTotalsAndSummary( outFile, record_counter );
outFile.close();
}
else
{
cout << "Trouble Opening File";
cout << "\n\n\t\t ** About to EXIT NOW! ** ";
}
}
else
{
cout << "Trouble Opening File";
cout << "\n\n\t\t ** About to EXIT NOW! ** ";
}
return 0;
}
int ReadData( ifstream & inFile, ofstream & outFile, char name[][MAX], int age[] )
{
int counter = 0;
inFile >> name[counter] >> age[counter]; // Priming Read
while ( !inFile.eof() )
{
cout << setiosflags( ios::left ) << setw( 25 )
<< name[counter] << resetiosflags( ios::left )
<< setw( 4 ) << age [counter] << endl;
counter++;
inFile >> name[counter] >> age[counter];
}
return counter;
}
void WriteOutputFile( ofstream &outFile, char name[][MAX], int age[], int counter)
{
outFile << " Here is the Output File" << endl;
for ( int r = 0; r <= counter; r++ )
{
outFile << setiosflags( ios::left ) << setw( 25 )
<< name[r] << setw( 4 )
<< resetiosflags( ios::left ) << age[r]
<< endl;
}
}
void PrintTotalsAndSummary( ofstream &outFile, int totalRecords )
{
// To screen
cout << "\n\n\t** Total Records: " << totalRecords << " **\n"
<< "\t\t The End \n";
// To file
outFile << "\n\n\t** Total Records: " << totalRecords << " **\n"
<< "\t\t The End \n";
}
File I am reading from (Chap_11_employee_data.txt):
"Alexis","Blough",1-1921,"CEO"
"Bill","Pay",1-7711,"Accounting"
"Willy","Makit",4-1595,"Sales"
"Marie","Murray",1-4986,"MIS"
"Cal","Caldwellowinski",5-0911,"MIS"
"Jamie","Johanasola",5-9999,"Marketing"
File I am writing to (Chap_11_Report.txt):
Here is the Output File
-858993460
** Total Records: 0 **
The End
Here is your input statement...
inFile >> name[counter] >> age[counter];
And the output file format is this...
"Alexis","Blough",1-1921,"CEO"
"Bill","Pay",1-7711,"Accounting"
The input statement reads the name till it encounters a space or an endline character. So in the first case it would read the whole line as there is no space in between the words. Next on, it would take input of age which is an int. It would start taking input of age from the second line, which is full of characters from the beginning. A character in integer stream is undefined behavior. That is the reason you are getting wrong results.
The problem is the mismatch of the file format with the input format. Try to synchronise them.
For reading white spaces as well, use inFile.get() or inFile.getline().
Your read has one problem:
while ( !inFile.eof() )
The problem is that the stream can go bad in a way that is not eof(). If this happens you will enter an infinite loop. So really you should check for bad().
while ( !inFile.bad() ) // check for eof and other error cases.
Normally this test is completely wrong. But you have managed to get around this by doing the following:
<Get Input>
while ( !inFile.bad() )
{
< DO WORK>
<Get Input>
}
The same affect can be achieved (in a more idiomatic way) with:
while ( <Get Input> )
{
< DO WORK>
}
The read (using >> or std::getline()) returns a reference to a stream. When this is used in a boolean context (like a while loop test) it is converted to bool (actually bool like for the language lawyers) that represents the state of the stream which is obtained by using bad. Thus the loop body is only entered if the read actually worked.
The input stream operators are very simplistic and any failure on input will set an internal failure bit inside the stream causing them to sieze up and not provide further input until the failure bit is reset.
Given the input you have provided this will fail:
inFile >> name[counter] >> age[counter];
The variable name[counter] represents a C-String and the the input operator >> when applied to a C-String will read until the first white space character (in this case newline). So here we assign:
"Alexis","Blough",1-1921,"CEO"
to this value.
We then try and continue reading using age[counter] an integer value. This tries to read an integer from:
"Bill","Pay",1-7711,"Accounting"
This will fail as the character '"' is not a digit.
What you should be doing is:
std::string name;
std::getline(inFile, name, ','); // Read upto the ',' character (and discard it)
// You may want to remove the quotes here.
int age = 0;
// Age is not defined in the input so set it manually.
std::string line;
std::getline(inFile, line); // Read and ignore the rest of the line.
Related
Okay, so I have an input file input.txtthat contains a CSV sequence: 1,1,1,2,2,3,3,4,4
and I am trying to separate it at the commas using a stringstream; however I'm getting a little problem here. For some reason the first number from the sequence is not even getting read by the stream. To show this, I created a some debugging code to see what is happening and I found out that the first number is being stored inside csvLine and every other number is being read and coverted just fine. I don't understand why just the first number is being omitted. Below is an example pic showing exactly what I mean. num should have the same exact values and Line, but it's not. It has all the values except the first one, which is being stored inside csvLine. Why is this happening?!
#include <iostream>
#include <fstream>
#include <sstream>
using namespace std;
int main(int argc, const char * argv[]) {
ifstream file;
string line;
string csvLine; //comma seperated value line
int num = 0;
file.open(argv[1]);
if(file.is_open()) {
while(getline(file, line)) { //get the whole line and use string stream to break at commas
cout << "\nLine: " << line << endl;
//using stringstream to seperate at commas
stringstream ss(line);
while(getline(ss, csvLine, ',')) {
cout << "csvLine: " << csvLine << " " << endl;
//using stringstream to convert to int
ss >> num;
cout << "num: " << num << " " << endl;
}
}
}
return 0;
}
The problem arises since you're using getline and then extracting integer from your stringstream
You should only use getline
while(getline(ss, csvLine, ','))
{
cout << "csvLine: " << csvLine << " " << endl;
num = std::stoi( csvLine ) ;
}
When you read getline(ss, csvLine, ',') the first time it reads the number followed by the the ','. For the next numbers it just reads the comma as the number was already extracted using ss >> num. That is, the simplest fix is to only read everything up to and including the comma after the loop was executed. Since the value of string extracting the comma isn't used it makes sense to use ignore() instead of std::getline():
for (; ss >> num; ss.ignore(std::numeric_limits<std::streamsize>::max(), ',')) {
// do something with the number
}
Restructuring the loop this way has the added benefit that it is checked whether reading the number was successful.
Good morning all.
I'm starting to learn c++ and i'm trying to make a prog that converts from one currency to another.
I made a text file "currency.txt" where i have all currencies, one after another, each with 4 lines:
Country, Currency description, Currency code, Exchange rate.
So far i made the following code:
#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
using namespace std;
struct currency {
string country;
string coin;
string code;
double rate;
};
int count_lines ( ifstream &myfile ){
string line;
int lines = 0;
if ( myfile.is_open() ){
while ( getline( myfile, line ) ){
++lines;
}
} else cout << "error";
myfile.seekg (0, ios::beg);
return lines;
}
void read_coins ( currency coins[], ifstream &myfile, int lines) {
string line;
if ( myfile.is_open() ){
for ( int n=0; n<lines; n++){
getline( myfile, line );
coins[n].country = line;
getline( myfile, line );
coins[n].coin = line;
getline( myfile, line );
coins[n].code = line;
getline( myfile, line );
stringstream(line) >> coins[n].rate;
}
} else cout << "error";
myfile.seekg (0, ios::beg);
}
int main(){
ifstream myfile ( "currency.txt" );
int lines;
lines = count_lines ( myfile )/4;
currency coins [lines];
read_coins (coins, myfile, lines);
for (int n=0; n<lines; n++){
cout << coins[n].country << '\t';
cout << coins[n].coin << '\t';
cout << coins[n].code << '\t';
cout << coins[n].rate << endl;
}
myfile.close ();
return 0;
}
But it's just not working. If i open the file inside all of the functions it works, but not like this.
I know there must be a problem for sure but i just can't figure it ou yet.
And i have another problem: the exchage rates have 10 decimal digits, but when i put it in my coins[n].rate, it comes only with 5 ou 6 decimal digits. Is there anyway to get all 10?
Can somebody help me please?
Thanks
If you're not using C++11, seekg doesn't reset the end-of-file state of the file.
Add myfile.clear() before seeking to the beginning.
The output of floating point numbers depends on the current precision of the stream.
The default is six (6).
Add
#include <iomanip>
and
std::cout << std::setprecision(10);
before output.
(But remember that floating-point is inexact in itself, so you won't necessarily get exactly the same number as in the file - only the closest one possible.)
I found a way to read the data into my array structs but i cannot control how many it reads. It will read all 14 entries in the input file but after it has read the 14 it continues for a couple lines then stops. However, if i place the code to read data inside any loop whether while or for, it starts printing huge numbers instead of what is contained in the file. Does anyone know why this happens? Is there a way around it
Input file looks as follows( exclude the dot):
There are 14 sets of data in the file. So, as shown below, set 1 would include georgia 76.4 10, then north carolina 95.5 20, and so on till 14 sets.
Data inside input file looks like this:
georgia
76.4 10
north carolina
95.5 20
and so on.
Need to print data to the screen like:
georgia 76.4 10
north carolina 95.5 20
etc.
The problem lies in my code were i attempt and horribly fail to read into the input file.
#include <iostream>
#include <fstream>
#include <cstdlib>
struct ATdata
{
string state;
double miles;
int shelters;
};
int readData( ifstream& input, struct ATdata data[] );
int main()
{
ifstream input;
char filename[256];
ATdata data[14];
int i;
cout << "Enter input file name: ";
cin >> filename;
input.open( filename );
if ( input.fail() )
{
cout << "Input file does not exist." << endl;
exit(1);
}
readData( input, data );
cout << i << endl;
return(0);
}
int readData( ifstream& input, struct ATdata data[] )
{
int i, j;
getline( input, data[i].state, '\t' );
input.ignore( 14, '\n' );
input >> data[i].miles;
input.ignore( 1, ' ' );
input >> data[i].shelters;
for ( j = 0; j < 14; j++ )
{
cout << data[j].state << data[j].miles << data[j].shelters << endl;
}
}
I apologize for all the info trying to be as clear as can be as to not look more idiotic.
Thank you have a nice day.
getline() takes an ostream& and a string. Since your types are not string, it gives you an error. I recommend reading in your input like this:
for (int i = 0; i < 14; i++ )
{
input >> data[i].state >> data[i].miles >> data[i].shelters;
}
BTW, your state is a char, that's 1 character. Make it an std::string.
The best way to get a whole line is to use std::getline. However, if you try to mix unformatted input with formatted input then it gets a bit tricky. You need lots of ignore calls and other guff. I think it is always clearer to read a whole line at a time, and then use a stringstream to parse that line.
Try this:
size_t readData( ifstream& input, struct ATdata data[], size_t max_items )
{
size_t i;
for ( i = 0; i < max_items; )
{
ATdata item;
getline(input, item.state);
string line_2;
if ( ! getline(input, line_2) )
break;
istringstream iss(line_2);
if ( ! (iss >> item.miles >> item.shelters) )
{
// skip malformed entry (or you could abort instead)
continue;
}
data[i++] = item;
}
return i;
}
Call it with:
size_t num_items = readData(input, data, sizeof data / sizeof data[0]);
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!
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.
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.
This question already has answers here:
Why is “while( !feof(file) )” always wrong?
(5 answers)
Closed 1 year ago.
I have started working on a program, and for the life of me I can't find a bug which continuously searches the eof and doesn't end. It is most certainly a problem with my fileread and widthcount functions, and they most likely have the same error. Is there a fix for this? It just keeps looping.
The file input is this
12.43 62.38 Los Angeles
21 59 Columbus, Ohio
0 15.58 Green Bay, Wisconsin
This continues for another 10 lines.
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <iomanip>
using namespace std;
void fileread(ifstream &ifFile, char newline, double &temp1, double &temp2, string city);
void widthcount(ifstream &ifFile, int &maxCount, char newline);
int main() {
double temp1, temp2, minTemp, maxTemp;
int maxCount;
char newline=' ';
string FileRead, city;
ifstream ifFile;
cout << "Please enter the location of the input file: ";
cin >> FileRead;
ifFile.open(FileRead.c_str());
if (ifFile.fail()) {
perror(FileRead.c_str());
exit(1);
}
widthcount(ifFile, maxCount, newline);
while(!ifFile.eof()) {
widthcount(ifFile, maxCount, newline);
}
ifFile.close();
ifFile.open(FileRead.c_str());
fileread(ifFile, newline, temp1, temp2, city);
while(!ifFile.eof()) {
fileread(ifFile, newline, temp1, temp2, city);
cout << left << setw(20) << city
<< right << setw(6) << fixed << setprecision(2) << temp1
<< right << setw(6) << fixed << setprecision(2) << temp2 << endl;
}
}
void fileread(ifstream &ifFile, char newline, double &temp1, double &temp2, string city) {
int charcount = 0;
ifFile >> temp1 >> temp2;
while (newline == ' ')
ifFile.get(newline);
while (newline != '\n' || !ifFile.eof()) {
charcount++;
ifFile.get(newline);
}
}
void widthcount (ifstream &ifFile, int &maxCount, char newline) {
double temp1, temp2;
int charcount = 0;
ifFile >> temp1 >> temp2;
ifFile.get(newline);
while (newline != '\n' && !ifFile.eof()) {
charcount++;
ifFile.get(newline);
cout << newline;
}
if (charcount > maxCount)
maxCount = charcount;
}
You need to check for failure (test .fail()), not end of file.
Typically .fail() is checked by using the stream object directly as condition.
E.g. while( f ) is equivalent to while( !f.fail() ).
Checking specifically for eof() is almost always a mistake -- for example, if you encounter some other error before reaching the end of the file, eof will remain false, but reading will fail (but since eof remains false, your loop will continue attempting to read and failing, forever).
Personally, I'd structure the code quite a bit differently. I'd start by creating a struct to represent one "record" from the file:
struct city {
double temp1, temp2; // horrible names, but I don't know what they represent.
std::string name;
};
Then I'd overload operator>> to extract the data for one city from a stream, and operator<< to display the data for a city:
std::istream &operator>>(std::istream &is, city &c) {
is >> c.temp1 >> c.temp2;
std::getline(is, c.name);
return is;
}
std::ostream &operator<<(std::ostream &os, city const &c) {
return cout << left << setw(20) << c.name
<< right << setw(6) << fixed << setprecision(2) << c.temp1
<< right << setw(6) << fixed << setprecision(2) << c.temp2;
}
Then I'd use those to read and write the data as god intended (with an algorithm):
int main(int argc, char **argv) {
// For the moment, cheat and take the file name from the command line
std::ifstream ifFile(argv[1]);
std::copy(std::istream_iterator<city>(ifFile),
std::istream_iterator<city>(),
std::ostream_iterator<city>(std::cout, "\n"));
return 0;
}
As an aside, I'd note that although you call widthcount, you never seem to use any result from it. At least for now, I've skipped over doing anything similar, since it didn't affect the result.
You should try something like
double t1,t2;
string s1,s2;
ifstream ifs;
ifs.open(Filename.c_str());
ifs>>t1>>t2>>s1>>s2;
while(ifs)
{
.......
do the calculations
.......
ifs>>t1>>t2>>s1>>s2;
}
This works for all the cases.If ,after the first read,ifs enters the fail state then rest of the file reading will be skipped and lines after the while loop will be executed.Other wise, rest of the lines will be read in the loop.You can change your requirement based on whether you want to read a string,a character or a line.