I am writing a simple program to take a user-supplied file, read the contents, and output email addresses found in the file. If the user supplied an invalid path/file name, I want to prompt the user to try again.

Right now, everything works properly if the first file name the user inputs is valid. If it's invalid, the program correctly identifies that and continues to prompt until a valid file name is provided. If the first file name supplied is invalid, the program bypasses the file parsing routine even though it reports a valid file name.

Here's what I have:

fileExists = false;
	while (!(fileExists)) {

		cout << "Enter name of the input file.\n";
		getline(cin, filename);
		cout << "\n\n";

		//remove any leading white space in filename
		while (filename.substr(0, 1) == " ") {
			length = filename.length();
			length--;
			filename = filename.substr(1, length);
		}

		inFile.open(filename.c_str());

		if (inFile.is_open()) {
			fileExists = true;
			filename = "";
			cout << "Enter the name of the output file.\n";
			getline(cin, filename);

			//remove any leading white space in filename
			while (filename.substr(0, 1) == " ") {
				length = filename.length();
				length--;
				filename = filename.substr(1, length);
			}

			outFile.open(filename.c_str());

			while(inFile) {
				inFile >> inValue;
				if (inValue.find("@") != string::npos) {
					outFile << inValue << endl;
				}
				inValue = "";		//clear inValue so final value doesn't repeat
			}
			outFile.close();
		} else {
			cout << "Input file does not exist\n\n";
			filename = "";
		}

		inFile.close();
	}

Let's say I have file c:\temp\myfile.dat. If the user enters it correctly the first time on line 5, everything works properly. If they enter c:\temp\myfil.dat the first time it will respond "Input file does not exist" and loop back up to ask for the input file name. If the 2nd time the user enters c:\temp\myfile.dat, the program recognizes that it's a valid file but doesn't enter the while loop starting on line 32 (I sent some output to console in the loop to check).

Any ideas?

Recommended Answers

All 9 Replies

Don't repeat your filename validation with a duplicate section of code after the first check. Use the first check as the only check.

Don't repeat your filename validation with a duplicate section of code after the first check. Use the first check as the only check.

I don't think I'm duplicating the check. I try to open the file on line 15 and check to see if it's open on line 17. If it's open, I ask for a file name for the output file. Where am I duplicating the file name validation?

Perhaps I've misread the problem you describe.

Try changing line 32 to while(inFile >> inValue) and remove line 33.

Try changing line 32 to while(inFile >> inValue) and remove line 33.

I like this better than what I had, and it helped with the problem of values repeating so I can remove line 37 too, but it didn't fix the problem I asked about.

The way it is now, with or without the changes to lines 32/33, if I enter a valid file name for the input file when prompted on the first run it works. If I enter an invalid file name, it outputs a message stating bad file name to cout, then asks for a new file name. If the 2nd time I enter a file name I enter a valid file name, it still reports bad file name and asks for a new one.

I'm stumped.

I had been thinking something along this line...

#include <iostream>
using std::cout;
using std::cin;
#include <string>
using std::string;
#include <fstream>
using std::ifstream;
using std::ofstream;

std::string get_filename(const char *prompt  = "filename?", 
                         const char *defname = "file.txt")
{
   string input, filename = defname;
   cout << prompt << "<" << defname << "> ";
   getline(cin, input);
   if ( input != "" )
   {
      return input;
   }
   return filename;
}

int main()
{
   ifstream ifs;
   ofstream ofs;
   string filename;

   do {
      filename = get_filename("input file? ", "file.txt");
      ifs.open(filename.c_str());
   } while ( !ifs.is_open() );
   cout << "opened " << filename << " for reading\n";

   do {
      filename = get_filename("output file? ", "output.txt");
      ofs.open(filename.c_str());
   } while ( !ofs.is_open() );
   cout << "opened " << filename << " for writing\n";

   // ...

   return 0;
}

After the failed attempt to open the file, inFile is in error state. You want to do inFile.clear(); to make it functional again.

After the failed attempt to open the file, inFile is in error state. You want to do inFile.clear(); to make it functional again.

That was exactly what I needed! Works the way I wanted it to now.

I'll have to play with this later when I'm more coherent - I'm interested in seeing how it works.

I had been thinking something along this line...

#include <iostream>
using std::cout;
using std::cin;
#include <string>
using std::string;
#include <fstream>
using std::ifstream;
using std::ofstream;

std::string get_filename(const char *prompt  = "filename?", 
                         const char *defname = "file.txt")
{
   string input, filename = defname;
   cout << prompt << "<" << defname << "> ";
   getline(cin, input);
   if ( input != "" )
   {
      return input;
   }
   return filename;
}

int main()
{
   ifstream ifs;
   ofstream ofs;
   string filename;

   do {
      filename = get_filename("input file? ", "file.txt");
      ifs.open(filename.c_str());
   } while ( !ifs.is_open() );
   cout << "opened " << filename << " for reading\n";

   do {
      filename = get_filename("output file? ", "output.txt");
      ofs.open(filename.c_str());
   } while ( !ofs.is_open() );
   cout << "opened " << filename << " for writing\n";

   // ...

   return 0;
}
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.