OFStream in vector failing to open file. Failbit is 1 badbit is 0.

I'm trying to move a dictionary into a group of bite-sized files based off of the length of the strings in each file (I'm ignoring strings of length 1 for obvious reasons). Since I don't know what the longest word is (and I'm not going to look for it), and I don't want redundant files, I decided to use a vector of output file streams that I would put all the words into, but I can't get the file to open.

I took a look at it and found the failbit is 1, but the badbit is 0, so apparently it's a logic error on opening the stream (http://www.cplusplus.com/reference/ios/ios/rdstate/). I looked online and decided to try using pointers, but that didn't help either, so now I'm asking what the problem might be, because I can't think of any reason why it isn't working.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
void createDictionary()
{
	//declare variables
	string dictionaryName;				//name of dictionary file
	ifstream dictionaryIn;				//file of original dictionary
	vector<shared_ptr<ofstream>> dictionaryOut;	//files where dictionary will be put based off of word length
	string word;					//input from the dictionary file
	vector<int> lengths;				//vector containing available lengths and their locations
	unsigned long long counter = 0;

	//get input
	cout << "Enter full name of dictionary to use (include the extension):  ";
	getline(cin, dictionaryName);

	//open dictionary
	const char *file = dictionaryName.c_str();
	dictionaryIn.open(file);
	if (!dictionaryIn.is_open())
	{
		cout << dictionaryName << " could not be opened.  Please make sure your file name is correct and try again.\nReturning to main menu.\n";
		return;
	}

	//set up dictionary
	cout << dictionaryName << " opened successfully.\nPlease wait while I set up the dictionary for quick searching for anagrams.\n";
	while (getline(dictionaryIn, word))
	{
		//loop variables
		int length = word.length();		//length of the word (used to separate words in the dictionary based off of length)
		int loc = locate(length, lengths);	//location of the file containing words of length "length"

		//single-length words do not have anagrams
		if (length == 1)
			continue;

		if (loc == -1)
		{
			counter++;
			//get file name
			stringstream name;
			name << length << ".txt";
			const char *dictionaryFile = name.str().c_str();

			//add file stream to vector
			//ofstream currentLength(dictionaryFile);
			dictionaryOut.push_back(make_shared<ofstream>(dictionaryFile));
			lengths.push_back(length);

			//get location and check that file is open
			loc = dictionaryOut.size() - 1;
			//loc = locate(length, lengths);
			//dictionaryOut[loc].open(dictionaryFile);
			if (!dictionaryOut[loc]->is_open())
			{
				cout << dictionaryOut[loc]->fail() << dictionaryOut[loc]->bad() << endl;
				cout << "Stopped on file " << counter << endl;
				cout << "There was an error in setting up your dictionary.  Please try again.\nReturning to main menu.\n";
				return;
			}
		}

		*dictionaryOut[loc].get() << word << endl;
	}

	for (int x = 0; x < dictionaryOut.size(); x++)
	{
		dictionaryOut[x]->close();
	}

	cout << "Dictionary set up successfully.\nReturning to main menu.\n";
}
Last edited on
If I understand correctly you want to store words of length x in a file x.txt

Slightly tested code using std::map instead of std::vector
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <iostream>
#include <fstream>
#include <string>
#include <algorithm>
#include <cctype>
#include <map>

int main()
{    
    std::map<std::string, std::ofstream> streams;
    std::ifstream ifs("input.txt");

    std::string instr;

    //read whitespace seperated words
    while (ifs >> instr)    
    {
        //remove non-alpha characters
        instr.erase(
            std::remove_if(instr.begin(), instr.end(), [](char c){ return !::isalpha(c); }), 
            instr.end());

        //construct filename
        auto fn = std::to_string(instr.length()) + ".txt";

        //store/construct stream and open file in append mode
        streams.emplace(fn, std::ofstream{ fn, std::ios::app });

        //store word
        streams.at(fn) << instr << '\n';
    }
}
Last edited on
So, I found the answer, and it was something weird that I wasn't used to. Back when I first started in C++, you could only open a file with a const char*, so if you wanted to open it based off of a string you didn't know beforehand, you had to convert your string. A friend of mine said to try using a string directly instead of converting it, and it worked for some reason. Why? I don't know, but that's programming, I guess.
Topic archived. No new replies allowed.