-
I/O with strings
The object of my program is to read one line from a file, read a line from another file, compare the two and if file 1 is smaller than file 2, then it is supposed to write from file 1 to the output line and read a new line from file 1. Otherwise, it writes the line from file 2 to the output file and reads a new line from file 2. The program is supposed to do this while the end of neither file 1 of file 2 has been reached. Then if there is any line in file 1 or file 2 that still has not been written to the output file, the program should write those lines. Here is my code:
Code:
#include <iostream>
#include <iomanip>
#include <cmath>
#include <cstdlib>
#include <fstream>
#include <cstring>
#include <string>
using namespace std;
int openFile(fstream& f, fstream& f1, fstream& f2);//function to open the files
void readWriteData(fstream& f, fstream& f1, fstream& f2);//function to read and write data
int main()
{
fstream outFile; //output
fstream inFile1;//input
fstream inFile2;//input
openFile(outFile, inFile1, inFile2);
cin.get();
return 0;
}
int openFile(fstream& outFile, fstream& inFile1, fstream& inFile2)
{
char outName[50];//storage of user input filename for the data file that is to be written to
char inName1[50];//storage of user input filename for the first data file that is to be read from
char inName2[50];//storage of user input filename for the second data file that is to be read from
cout << "Please type the name of the first input file, including the extension: ";//requests user input of filename
cin >> inName1;
cout <<'\n';
inFile1.open(inName1, ios::in);
if (inFile1.fail())//if file cannot be opened, a message will display
{
cerr << "Could not open " << inName1 << "!" << endl;
return EXIT_FAILURE;
}
cout << "Please type the name of the second input file, including the extension: ";//requests user input of filename
cin >> inName2;
cout <<'\n';
inFile2.open(inName2, ios::in);
if (inFile2.fail())//if file cannot be opened, a message will display
{
cerr << "Could not open " << inName2 << "!" << endl;
return EXIT_FAILURE;
}
cout << "Please type the name of the output file, including the extension: ";//requests user input of filename
cin >> outName;
cout <<'\n';
outFile.open(outName, ios::out);
if (outFile.fail())//if file cannot be opened, a message will display
{
cerr << "Could not open " << outName << "!" << endl;
return EXIT_FAILURE;
}
readWriteData(outFile, inFile1, inFile2);
return 0;
}
void readWriteData(fstream& outFile, fstream& inFile1, fstream& inFile2)
{
string in1;
string in2;
do
{
getline(inFile1, in1);
getline(inFile2, in2);
if (strcmp(in1.c_str(), in2.c_str()) < 0)
{
outFile << in1 << '\n';
outFile << in2 << '\n';
}
else if (strcmp(in1.c_str(), in2.c_str()) > 0)
{
outFile << in2 << '\n';
outFile << in1 << '\n';
}
else if (strcmp(in1.c_str(), in2.c_str()) == 0)
{
outFile << in1 << '\n';
outFile << in2 << '\n';
}
}
while (!inFile2.eof() || !inFile1.eof());
inFile1.close();
inFile2.close();
outFile.close();
}
When I use this code, there are duplicate lines put to the output file. If I use this code:
Code:
#include <iostream>
#include <iomanip>
#include <cmath>
#include <cstdlib>
#include <fstream>
#include <cstring>
#include <string>
using namespace std;
int openFile(fstream& f, fstream& f1, fstream& f2);//function to open the files
void readWriteData(fstream& f, fstream& f1, fstream& f2);//function to read and write data
int main()
{
fstream outFile; //output
fstream inFile1;//input
fstream inFile2;//input
openFile(outFile, inFile1, inFile2);
cin.get();
return 0;
}
int openFile(fstream& outFile, fstream& inFile1, fstream& inFile2)
{
char outName[50];//storage of user input filename for the data file that is to be written to
char inName1[50];//storage of user input filename for the first data file that is to be read from
char inName2[50];//storage of user input filename for the second data file that is to be read from
cout << "Please type the name of the first input file, including the extension: ";//requests user input of filename
cin >> inName1;
cout <<'\n';
inFile1.open(inName1, ios::in);
if (inFile1.fail())//if file cannot be opened, a message will display
{
cerr << "Could not open " << inName1 << "!" << endl;
return EXIT_FAILURE;
}
cout << "Please type the name of the second input file, including the extension: ";//requests user input of filename
cin >> inName2;
cout <<'\n';
inFile2.open(inName2, ios::in);
if (inFile2.fail())//if file cannot be opened, a message will display
{
cerr << "Could not open " << inName2 << "!" << endl;
return EXIT_FAILURE;
}
cout << "Please type the name of the output file, including the extension: ";//requests user input of filename
cin >> outName;
cout <<'\n';
outFile.open(outName, ios::out);
if (outFile.fail())//if file cannot be opened, a message will display
{
cerr << "Could not open " << outName << "!" << endl;
return EXIT_FAILURE;
}
readWriteData(outFile, inFile1, inFile2);
return 0;
}
void readWriteData(fstream& outFile, fstream& inFile1, fstream& inFile2)
{
string in1;
string in2;
do
{
getline(inFile1, in1);
getline(inFile2, in2);
if (strcmp(in1.c_str(), in2.c_str()) < 0)
{
outFile << in1 << '\n';
outFile << in2 << '\n';
}
else if (strcmp(in1.c_str(), in2.c_str()) > 0)
{
outFile << in2 << '\n';
outFile << in1 << '\n';
}
else if (strcmp(in1.c_str(), in2.c_str()) == 0)
{
outFile << in1 << '\n';
outFile << in2 << '\n';
}
}
while (!inFile2.eof() && !inFile1.eof());
do
{
if (inFile1.eof())
{
getline(inFile2, in2);
outFile << in2 << '\n';
}
else if (inFile2.eof())
{
getline(inFile1, in1);
outFile << in1 << '\n';
}
}
while (!inFile2.eof() || !inFile1.eof());
inFile1.close();
inFile2.close();
outFile.close();
}
There are no duplicates but then the remainder of the output is not alphabetical. Does anyone know of a better way I can achieve what I want to do?
-
C++ strings can be compared directly - and your comparisons are a bit overcomplicated - so simplified I'd do like this:
Code:
// Since equal strings can be in "either order" and still be correct, we just let the first case handle that.
if (in1 <= in2)
{
outFile << in1 << '\n';
outFile << in2 << '\n';
}
else
{
outFile << in2 << '\n';
outFile << in1 << '\n';
}
There is no need to get the C-string from a C++ string to compare the strings.
If you still insist on using c_str() to get the string, why not do:
Code:
// Since equal strings doesn't matter, just cover this case here, rather than
// a separate case.
if (strcmp(in1.c_str(), in2.c_str()) <= 0)
{
outFile << in1 << '\n';
outFile << in2 << '\n';
}
// As the only other alternative, we swap the strings. No need to compare the strings - they haven't changed.
else
{
outFile << in2 << '\n';
outFile << in1 << '\n';
}
This way, at least you are not comparing the same string up to 3 times (the compiler MAY realize that the strcmp() function always returns the same thing for the same input, but that's far from guaranteed).
I prefer the first code-sequence.
--
Mats