Normally, you would use a different approach. You would simply open both input and output files and then do the task in one shot.
But, obviously, the task is, to have only one stream open at the same time. And maybe, it should teach you how to use tellg
and seekg
functions.
And one of the most important things that you need to do: Please always check the return value of each function call. For read functions, this is an absolute must.
Then, handle potential errors, or states.
You can and should also use those return values for the control logic in your program.
What you should additionally know is, that, if stream variables go out of scope, they will automatically close the associated file. Please make use of this property.
Then, the solution: We need to set up a variable with the current file position. At the beginning, this is 0. Then we read data and, store the new file position after reading. We can close now the source file, because, we know the position of the next characters to read. So, close the file, and do the “vowel”-work. Simply check, if a character is a vowel, and then write it to the destination file.
Do this, until we get any kind of error of “EOF” (end of file).
A potential solution is shown below. I put many comments in the file for easier understanding.
Please see:
#include <iostream>
#include <fstream>
#include <string>
const std::string sourceFileName{ "test.txt" };
int main() {
// Define the filename for the destination file
std::string destinationFileName = "vowel_" + sourceFileName;
// Here we will store the current file position
std::ifstream::pos_type readPosition{};
// We will use a boolean variable to indicate, how long we want to read
bool continueToRead{ true };
// Read the source file in a while loop
while (continueToRead) {
// Open the source file for reading
std::ifstream sourceFileStream{ sourceFileName };
// Check, if the file could be opened.
// This calls the "bool" function of the stream, to check, if everything is OK
if (sourceFileStream) {
// Source file could be opened. Set the file read pointer to the last known position
if (not sourceFileStream.seekg(readPosition)) {
// If thís did not work (end of file or something)
continueToRead = false;
}
else {
// Read one line and check, if that worked.
std::string line{};
if (std::getline(sourceFileStream, line)) {
// Now we need to store the current file position for the next loop run
readPosition = sourceFileStream.tellg();
// Because, we want to have only one file stream open at a time,
// we will now close the input file stream
sourceFileStream.close();
// We may need to write to the output file. Open this now and check,
// if it could be opened. Set file pointer to end with "app"
std::ofstream destinationFileStream(destinationFileName, std::ios::app);
// Now iterate over the source line string and write vowels, if necessary
for (const char c : line) {
// check, if c is a vowel
if ((c == 'a') or (c == 'e') or (c == 'i') or (c == 'o') or (c == 'u')
or (c == 'A') or (c == 'E') or (c == 'I') or (c == 'O') or (c == 'U')) {
// Write vowel to destination file
destinationFileStream << c;
}
}
// Write final newline character
destinationFileStream << std::endl;
// Here the destinationFileStream will go out of scope and closed automatically
}
else {
// Could not read data. Stop loop
continueToRead = false;
}
}
}
else {
// Source file could not be opened.
std::cout << "\nError: Could not open source file '" << sourceFileName << "'\n\n";
continueToRead = false;
}
}
}