Why won't this code open a file for output?
April 6, 2015 4:59 PM   Subscribe

I'm learning C++ and I have this code that's supposed to ask a user for the name of a file to read from, then perform some editing of what it read, and then write the result to another file, the name of which was also provided by the user. The code opens and reads and performs the edits just fine, but reports that it cannot open the file for output. Out put to the screen works fine with cin >>.

I've tried giving it the name of a file that I previously created and giving the name of a file that doesn't yet exist. If it's a file that doesn't yet exist, an examination of the file structure shows that the program created the file but could not write to it. I haven't been able to find anything anywhere else (e.g. stackoverflow, cpp tutorial) that I haven't already tried. Any suggestions are most welcome.
#include<iostream>
#include<fstream>
#include<string>
#include<cctype>
using namespace std;


int main()
{
	string inputName;
	string outputName;
	string test;
	
	
	char ch;
	

	//ask user for two files names.  one is for input and the other for output
	cout << "Please enter the name of the input file, including its extension: ";
	cin >> inputName;
	cout << "Please enter the name of the file to write to, including its extension: ";
	cin >> outputName;

	fstream inFile("inputName", ios::in);
	fstream outFile(outputName, ios::out);

	inFile.open(inputName, ios::in);
	if (!inFile)
	{
		cout << "Could not open file";
		return 0;
	}

	outFile.open(outputName);

	if (!outFile)
	{
		cout << "Could not open file.\n";
		return 1;
	}

	inFile.get(ch);
	cout.put(toupper(ch));
	while (!inFile.eof())
	{	
		inFile.get(ch);
		if (ch == 46)
		{
			cout.put(ch); 
			inFile.seekg(1L, ios::cur);
			inFile.get(ch);
			cout.put(toupper(ch));
		}
		else cout.put(tolower(ch));
		
	}

	outFile << flush;
	outFile.close();
	inFile.close();

	return 0;
}

posted by johnofjack to Computers & Internet (13 answers total)
 
InFile("inputname",

Probably shouldn't be quoted, I think its using the string inputname instead of the variable/ what the user entered, contrast with outputname, just first impression
posted by TheAdamist at 5:12 PM on April 6, 2015 [3 favorites]


Best answer: It looks like you're opening the output file twice, once with the "fstream outFile(...)" and once with outFile.open(...)". Just remove the "open" call.

(The same is true for the input file, once you fix the bug noticed by TheAdamist above.)
posted by mbrubeck at 5:16 PM on April 6, 2015 [1 favorite]


First thing is probably to check the permissions on the directory where the output file is - I apologize if that's too obvious. (It always used to drive me crazy when I'd lose something and my Mom would follow me around, asking if I had looked in completely obvious places that I had already checked.......)
posted by thelonius at 5:17 PM on April 6, 2015



fstream inFile;
ofstream outFile;

inFile.open(inputName, ios::in);
if (!inFile)
{
cout << "Could not open file";
return 0;
}

outFile.open(outputName, ios::out);

if (!outFile)
{
cout << "Could not open file.\n";
return 1;
}


Sorry for lack of indents. That will at least run for me; outputFile is 1 after the open. Not sure exactly what this is supposed to be doing but give it a shot. No idea how to explain whatever the bug was as I am really not a C++ programmer.
posted by vogon_poet at 5:18 PM on April 6, 2015


By the way, the code compiles runs fine for me once I fix the "inputName" bug and comment out the "open" calls. But you write to "cout" in a bunch of places where you probably want to write to outputFile instead.
posted by mbrubeck at 5:22 PM on April 6, 2015 [1 favorite]


Response by poster: Should've mentioned that...without the "" around inputname, the program will not open the file to read from . And if I put "" around outputName, the program will create a file called outputName regardless of what the user types for the name of the output file. Weird, and since I'm a noob, I have no idea why that is.
posted by johnofjack at 5:22 PM on April 6, 2015


Best answer: You have these two lines in your code:
    	fstream inFile(inputName, ios::in);
	inFile.open(inputName, ios::in);
These are two different ways of writing the same thing. Both lines try to open the file. The second one fails because the file is already open. Instead of writing both of these lines, you should only use one or the other.

Either do just this:
    	fstream inFile(inputName, ios::in);
or just this:
    	fstream inFile;
	inFile.open(inputName, ios::in);
but not both.
posted by mbrubeck at 5:27 PM on April 6, 2015 [1 favorite]


Best answer: In addition to mbrubeck's comment, stated more explicitly: You open a file, do NOT close it, and attempt to open it again. This is why your first "inputFile" needed quotes (it doesn't, it's just opening a different file.) This is why your outputFile failes to open--because it is already opened.
posted by ethidda at 5:30 PM on April 6, 2015 [2 favorites]


after got access to a compiler, yeah, the double opening of the files is causing problems on input(after fixing the hardcoded string) & output, not that i parsed whats its supposed to be doing with a period (ascii 46).
if you look at:
http://en.cppreference.com/w/cpp/io/basic_fstream/basic_fstream

variety 2/note 3 or something like that it does the open when you pass a filename in on the constructor, and the double open does bad things.

ps, to others, since it puzzled me: a side note, depending on the compiler(esp on linux) you might need to pass
-std=c++11
so it compiles, since the fstream constructor being used relies on c++11 behavior to take a string and not just a char*
pps. its 2015, c++11 shouldn't be special and new.
posted by TheAdamist at 5:49 PM on April 6, 2015


Response by poster: thank you all - you're correct; it's trying to open the file twice. correcting for that, I was able to get the program to succcessfully write to the file. HOWEVER, and a snippet of code follows here, it is writing the ASCII codes for each character rather than the character itself. I had included cout statements so that it would display to the screen as well, so I could see what it was doing. It displays to the screen exactly as it should, but not to the file:

while (!inFile.eof())
{
inFile.get(ch);
if (ch == 46)
{
cout.put(ch);
outFile << (ch);
inFile.seekg(1L, ios::cur);
inFile.get(ch);
cout.put(toupper(ch));
outFile << (toupper(ch));
}
else
{
cout.put(tolower(ch));
outFile << (tolower(ch));
}
}
posted by johnofjack at 5:58 PM on April 6, 2015


Best answer: Look at http://linux.die.net/man/3/toupper . toupper takes an int and returns an int. Your 'ch' of type 'char' is getting implicitly converted to an int when you call toupper on it. A couple of ways to fix it. Try something like 'ch = toupper(ch);' instead of streaming the result of toupper to the file. This will cast the int back to a char. Alternatively you can probably call outFile.put(toupper(ch)) similarly to how you call cout.put.

As to why it works when you call cout.put, if you look up the docs for ostream::put, you'll find it takes a char. The cast from int to char is performed when you call the function.
posted by tz at 6:09 PM on April 6, 2015


Response by poster: Thanks tz; I had just come to that realization as well. As it now stands, the program works correctly. Thank you all for putting me on the right track.
posted by johnofjack at 6:29 PM on April 6, 2015


Just to add a general point to the code critiques above - the above is fine for "futzing around with" code, but if you ever did this for real, you’d probably be consuming and outputting unicode & should probably be using the appropriate libraries. toupper() and friends will fail with inputs like 'ß', which has multi-character uppercase equivalent (most of the time at least!).
posted by pharm at 12:53 PM on April 7, 2015


« Older New job in Watertown (MA), so many logistics   |   Are my mattress expectations too high? Newer »
This thread is closed to new comments.