There isn't ever an exact duplicate to get you started, but taking things piece-by-piece using cppreference.com as your reference you will begin to work your way through the problem.
Your task here presents a couple of challenges. You will need to open and validate both an input stream and output stream to read and write data to a file. While you can simply open the input file for reading, there are several output file modes you need to consider std::basic_ofstream::open. After opening each file you want to validate that each file is open std::basic_fstream::is_open
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
int main (int argc, char **argv) {
if (argc < 3) { /* validate arguments for infile and outfile names given */
std::cerr << "error: insufficient input\n"
"usage: program infile outfile\n";
return 1;
}
std::ifstream infile (argv[1]); /* open input file */
if (!infile.good()) { /* validate it is open for reading */
std::cerr << "error: file open failed '" << argv[1] << "'\n";
return 1;
}
/* open output file */
std::ofstream outfile (argv[2], std::ios::out | std::ios::trunc);
if (!outfile.good()) { /* validate it is open for writing */
std::cerr << "error: file open failed '" << argv[2] << "'\n";
return 1;
}
You have two lines of data to read from the file. The first is the name which you will want to keep together and can be read into a std::basic_string. The next line has salary
, bonus
and taxes
all on one line. Here you have two options:
- attempt to read from the file using the
>>
operator into each of salary
, bonus
and taxes
-- but that will leave you with the problem of the '\n'
remaining unread in the input stream needing to std::basic_istream::ignore the remaining characters in the line before your next attempted read of the next name
; or
- you read the next line exactly the same way you did the first, into a
std::string
, which will consume the entire line leaving the input stream read for your next attempted read, but then you will need split the line into salary
, bonus
and taxes
using std::basic_stringstream
There are a number of advantages with using the second option. You read your first line and assign the result to name
and you validate line.length()
(or name.length()
) is not zero to ensure you have read a valid name.
If so you proceed to read the next line -- the exact same way and create a std::stringstream
from the line you read and then validate the read of salary
, bonus
and taxes
from the std::stringstream
using the >>
operator -- knowing that regardless the result of the read from the std::stringstream
, your infile
is read for your next attempted read of name
.
On a successful read of salary
, bonus
and taxes
from the std::stringstream
you can write name
, salary
, bonus
and taxes
to outfile
and loop to read your next name
(and repeat until your run out of name
and salary
, bonus
and taxes
lines to read.
std::string line {}; /* string to hold line */
while (getline (infile, line)) { /* read name line, validate */
if (!line.length()) { /* if line is empty, bail */
std::cerr << "error: name empty\n";
break;
}
std::string name = line; /* assign line to name */
unsigned salary, bonus, taxes; /* vars for rest */
if (!getline (infile, line)) { /* read line of salary, bonus, taxes */
std::cerr << "error: no data following '" << name << "'\n";
break;
}
std::stringstream ss(line); /* create stringstream from line */
/* read values from stringstream -- validate */
if (!(ss >> salary >> bonus >> taxes)) {
std::cerr << "error: reading salary, bonus taxes\n";
break;
}
/* write result to outfile */
outfile << name << '\n' << salary << " " << bonus << " " << taxes << '\n';
}
}
(note: those are the two halves of the complete program)
Example Input File
If you have an input file of:
$ cat dat/infile.txt
Giselle Robinson Accounting
5600 5 30
Compile With Warnings Enabled
Always compile with warnings enabled, and do not accept code until it compiles without warning. To enable warnings add -Wall -Wextra -pedantic
to your gcc/clang
compile string (also consider adding -Wshadow
to warn on shadowed variables). For VS (cl.exe
on windows), use /W3
. All other compilers will have similar options. Read and understand each warning -- then go fix it. They will identify any problems, and the exact line on which they occur. You can learn a lot by listening to what your compiler is telling you.
$ g++ -Wall -Wextra -pedantic -Wshadow -std=c++14 -Ofast -o bin/infileoutfile infileoutfile.cpp
Example Use
You can provide both the input and output filenames as the first two arguments to your program:
$ ./bin/infileoutfile dat/infile.txt dat/outfile.txt
Resulting Output File
Resulting in the output file created:
$ cat dat/outfile.txt
Giselle Robinson Accounting
5600 5 30
Now this isn't the only way to approach reading your file and creating the output, but these are the considerations and thought process you should be working through approaching any of your new projects. Look things over and let me know if you have further questions.
Further Readings
Why is “using namespace std;” considered bad practice? and should you ever be tempted Why !.eof() inside a loop condition is always wrong. and also worth understanding C++: “std::endl” vs “\n”