Reading from a file

Pages: 123
So, I need to read from a file and display the text exactly as it is. I was told I need to use getline, to include the white spaces, and also use stringstream >> . Also Im not sure how to even use stringstream, I read stuff like this: https://www.cplusplus.com/reference/sstream/stringstream/
but It seems difficult to read, and has a lot of things I don't understand.
file1 should look like this:
file 1: This &%file should!!,...







have exactly 7 words.
file1.txt has 7 words.
instead im getting this:

aexcl od.

It needs to loop until the user types "quit" for file selection. It also needs to loop for reading the file and another loop for counting the number of words in a file, and a last loop for validation. Here's my code.

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
#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
using namespace std;
int main()
{
    ifstream inputFile;

    string wordFile;
    string output;
    //string words;

    stringstream words;

    char letter = 0;

    int count = 0;

    cout << "    *** A SIMPLE FILE PROCESSING PROGRAM ***\n\n";
    cout << "Enter a filename or type quit to exit: ";
    getline(cin, wordFile);
    //cin.clear();
    //cin.ignore();

    // Open input file
    inputFile.open(wordFile);

    if (!inputFile.fail())
    {
        while (getline(inputFile, wordFile))
        {
            for (count = 0; count < wordFile.length(); count++)
            {
                inputFile.get(letter);
                if (!inputFile.eof())
                {
                    cout << letter;
                    //words >> output;
                    //cout << letter;
                    //inputFile >> letter;
                    count++;
                    inputFile >> letter;
                }
            }
        }
        // Close the file
        inputFile.close();
    }
    else
    {
        cout << "File not found. Enter the correct filename: ";
    }


    return 0;
}



Last edited on
you already got the data. the for loop over wordfile.length() appears to be trying to read the same data from the file again... you don't need that.
to display what was in the file, all you need is:

while (getline(inputFile, wordFile))
{
cout << wordFile << endl;
}

you also do not need a stringstream. If you have to use one, you will need to make up something to do with it.
Last edited on
Ok, I tried that and it fixed it, now I just need to add a counter to count the words in the file. Also, I was just thinking stringstream because it just seems more logical to read word by word rather than char to char, But I realize it is reading word by word now.
If you use a C++ container, like a std::vector or std::list, the count is done automatically for you if you store whole words as the vector's elements.
http://www.cplusplus.com/reference/vector/vector/size/

With a test file (test.txt) as follows:
This is a test.
Some     more            text
And   even more         text

Easy peasy way to count the number of words in a file as long as each is separated by an end-of-line or whitespace (one or more spaces)
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
#include <iostream>
#include <string>
#include <vector>
#include <fstream>

int main()
{
   std::ifstream ifs("test.txt");

   // check to see if the file was actually opened
   // ALWAYS check, unless you like having your butt in a sling
   if (!ifs)
   {
      // opening the file failed, let's bail!
      std::cout << "Unable to open the file!\n";
      return -1;
   }

   // create a temp string to hold each word read from the file
   std::string temp;

   // create a vector to hold each read word
   std::vector<std::string> word_vec;

   // read each word in a loop using the extraction operator>>
   // the loop will end when no more words to extract
   while (ifs >> temp)
   {
      // push back each read word into the vector
      word_vec.push_back(temp);
   }

   // what's the number of read words?  the size of the vector
   // http://www.cplusplus.com/reference/vector/vector/size/
   std::cout << "The number of words read from the file: " << word_vec.size() << '\n';
}

The number of words read from the file: 11
Oh I don't think I can use vectors yet, that's next week I think we go into functions. It's about time to learn it soon because all I see on the internet are "void" and things like that.
So I've updated my code, I got a little farther, but now my count is getting erased at the end. I think I need to find a different way to capture count, because the end of loop is erasing count?
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
int main()
{
    ifstream inputFile;

    string wordFile;
    string output;
    //string words;


    char letter = 0;

    int count = 0;
    int numberOfWords = 0;

    cout << "    *** A SIMPLE FILE PROCESSING PROGRAM ***\n\n";
    cout << "Enter a filename or type quit to exit: ";
    getline(cin, wordFile);

    // Open input file
    inputFile.open(wordFile);



    if (!inputFile.fail())
    {
        while (getline(inputFile, wordFile))
        {
            cout << wordFile << endl;
        }
        while (inputFile)
        {
            getline(inputFile, wordFile);
            numberOfWords = count++;
        }
        
        // Close the file
        inputFile.close();
    }
    else
    {
        cout << "File not found. Enter the correct filename: ";
    }

    cout << "number of words are : " << numberOfWords;

    return 0;
}
1
2
3
4
5
6
7
8
9
        while (getline(inputFile, wordFile))
        {
            cout << wordFile << endl;
        }
        while (inputFile)
        {
            getline(inputFile, wordFile);
            numberOfWords = count++;
        }

This combination of looping doesn't make sense.
In the first loop, you're already going through each line in the file, until there are no more lines left.
The second loop therefore won't run, because you're already at the end of the file.

If you want to count whitespace-delimited words, just do what jonnin/FurryGuy suggested.
1
2
3
4
5
string word;
while (inputFile >> word)
{
    numberOfWords++;
}


PS: Your 'count' and 'numberOfWords' variables seem redundant.
Last edited on
Sorry I tend to make more than needed variables when I code, I delete them later.
Also, I do have that written and just tested it. I'm still getting 0 words. I need to keep white space intact, but only count non-whitespace characters as words.
1
2
3
4
5
6
    while (inputFile >> wordFile)
    {
        numberOfWords++;
    }

    cout << "number of words are : " << numberOfWords;


Ok, if I put that loop above all the rest of my code, it prints out 7, but then it skips the if statement and goes to the else, and says file not found.
Last edited on
I'm not following. Just reply with your most up-to-date code.
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
int main()
{
    ifstream inputFile;

    string wordFile;
    string output;
    //string words;

    char letter = 0;

    int count = 0;
    int numberOfWords = 0;

    cout << "    *** A SIMPLE FILE PROCESSING PROGRAM ***\n\n";
    cout << "Enter a filename or type quit to exit: ";
    getline(cin, wordFile);

    // Open input file
    inputFile.open(wordFile);

    while (inputFile >> wordFile)
    {
        numberOfWords++;
    }

    if (!inputFile.fail())
    {
        while (getline(inputFile, wordFile))
        {

            cout << wordFile << endl;
        }

        // Close the file
        inputFile.close();
    }
    else
    {
        cout << "File not found. Enter the correct filename: ";
    }

    cout << "number of words are : " << numberOfWords;

    return 0;
}


So, it must be at the end of file while counting the number of words since I get the right number now. Is there a non-advanced way at starting over in the file? It seems like the hint my teacher gave me is to open and close more than once, and to clear at the end of the loops.
Last edited on
@OP
Please show us the original untouched, entire and complete versions of two things:
1. The assignment question.
2. The sample text file you have to analyze.

If you can't or won't then sorry to say you are just peeing into the wind and everybody, including yourself, are just dancing around despite the valiant attempts from all concerned in trying to communicate and help you out.
1. The question:
Write a program that prints out the file data and number of words in a file of text. We will define a word to be any sequence of non-whitespace characters. So "hi&there...mom" would be considered a single word. Solve this file data processing programming challenge using appropriate nested looping constructs such as (1) loop to allow for multiple file reads (2) loops to read file data as strings and/or character-by-character (3) loops for file validation routines.

2. Sample text:
This &%file should!!,...



have exactly 7 words.

text:
This is a &%file that should!!,...



have exactly 10 words.

text:
This is a &%file that should!!,...


This file must have several spaces at the end of the file.
have 21 words.

text:
This &%file that has!!,...

'

This file must have several spaces at the end of the file.
19 words.

text:
Mr. &%Brown can moo!!,...

'

can you? This file should have several blank lines before the end of the file.

22 words.


Oh and he specifies input validation here:
Appropriate validation methods should be used to ensure that the file stream is not in fail state. In other words you will need to include validation routines to check the following (1) whether the data file opened successfully and (2) the data read from the file matches the variable (datatype) into which the value will be stored. Failure to do so will mean that your program may run but will not produce correct output
Last edited on
Lines 21-24 is what is doing the actual work of counting the number of words in the file.
Once this loop is complete, the file stream will have been exhausted, and its fail() flag will be tripped to true.

You should be checking for inputFile.fail() right after you open the file, before you attempt to parse the file, not after.

You also do not want your loop on lines 28 - 32; this is counting lines in the file, not words.

These lines of code are the core of the logic:
1
2
3
4
5
6
7
8
9
10
11
12
13
inputFile.open(wordFile);
if (!inputFile)
{
    cout << "Error opening file\n";
    return 1;
}

string word;
while (inputFile >> word)
{
    numberOfWords++;
}
cout << "Number of words in file: " << numberOfWords << '\n';
Last edited on
"Ok, if I put that loop above all the rest of my code, it prints out 7, but then it skips the if statement and goes to the else, and says file not found." -- I was just putting it up there so I could test what it was doing. I understand checking for fail.
@OP Thanks.
This dramatically clarifies the situation.

Why the teacher has made it so complicated with all this multiple loop nonsense is anybodies guess.

All you have to do is read the file character by character and count, based on a simple non-space character followed by a whitespace character 'tokenizer' via peek()

All you need is a counter, no vector ...

Read the file into a stringstream and analyse that stream if you have to. It's all the same, as mentioned earlier, just a redundant waste of effort except for doing what is suggested - ignore it if you can without losing marks.

Why you would have to open, close and re-open the file is bizarre. Just do it to get the marks too? :)

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
#include <iostream>
#include <string>
#include <sstream>
#include <fstream>

using namespace std;

int main()
{
    ifstream source_file;
    
    string file_name;
    stringstream file_contents;
    
    char current_letter = '?';
    char next_letter = '?';
    
    int count = 0;
    
    cout
    << "    *** A SIMPLE FILE PROCESSING PROGRAM ***\n\n"
    << "Enter a filename or type quit to exit: ";
    
    getline(cin, file_name);
    source_file.open(file_name);
    
    if (!source_file)
    {
        cout << "File not found\n";
        return -99;
    }
    
    while (source_file >> noskipws >> current_letter) // <--
    {
        next_letter = source_file.peek();
        if ( !isspace(current_letter) && isspace(next_letter)) // <--
        {
            count++;
        }
    }
    cout << "Word count: " << count << '\n';
    
    source_file.close();
    cout << "Program ends\n";
    
    return 0;
}


For the last example text file:
  *** A SIMPLE FILE PROCESSING PROGRAM ***

Enter a filename or type quit to exit: count_words_3.txt
Word count: 22
Program ends
Program ended with exit code: 0


And that .txt file is:
Mr. &%Brown can moo!!,...

'

can you? This file should have several blank lines before the end of the file.

22 words.
Last edited on
Well, I have found a solution to this problem from years ago on this site, however it does nothing useful to this actual problem (which is usually the case). This means they didn't understand the problem or the problem has changed over time, possibly becoming harder too. I was hoping to continue using strings in this code as I just think it's more logical to do it that way. It not only has to give a word count but display the text file verbatim, in the output. I tried using stringstream, and the link I posted above on first post is just hard to understand and read. The examples I've tried to follow haven't made it right, and I forget how many I've done. The opening and closing files was just my idea. I'll try to implement the code you have there, but I have a lot of rules to follow, like I can only use a return at the end of a program.

*also this website is very glitchy, I've gotten post errors randomly a lot now, and also randomly signed out.
Last edited on
@OP
I fail to see what you are on about unless it's just to have a good ol' moan and whine. We all let our studies get us down at times so don't feel alone - perhaps just get away from it for a while and enjoy the break/fresh air - with a mask if necessary.

There's nothing to stop you from using, ignoring, modifying, adapting any of the contributions here or elsewhere to suit your agenda, whatever it is.

Try a cout here and there to display the results - you can add the current_letter to build each 'word' as the loop whirls around if you understand what the 'tokenizer' separation does. HINT: the text file doesn't contain words. The contents are separated by a sequence of 2 characters - see my if statement.

Please feel free to have only a single return or 1000 of them at any suitable/legal place you like.

And, sorry I can't help on your internet connection - again you're not alone - shit happens :(
So I added cout in many places like you said, not sure if this was the idea, there's probably other ways to do it, but I put ("output" is a string I threw in there just to test) "output += current_letter;" right above "next_letter = source_file.peek();" It is now printing out the file exactly. The count is off, showing 6 instead of 7, but I can just set count to 1 and it should be good.
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
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>

int main()
{
	std::string fnam;

	std::cout << "Enter file name: ";
	std::getline(std::cin, fnam);

	std::ifstream ifs(fnam);

	if (!ifs)
		return (std::cout << "Cannot open file\n"), 1;

	size_t wcnt {};

	for (std::string line; std::getline(ifs, line); std::cout << line << '\n') {
		std::istringstream iss(line);

		for (std::string wrd; iss >> wrd; ++wcnt);
	}

	std::cout << "\nContains " << wcnt << " words\n";
}



Enter file name: test2.txt
This is a &%file that should!!,...


This file must have several spaces at the end of the file.
have 21 words.




Contains 21 words


For input string stream, initialise it with a string and then treat it the same way you would reading from a file stream. Easy.
Last edited on
Excellent. I'm glad you have solved it under your own steam. That's the best way :)

( Your count experience sounds a bit strange though. But that's not to say it's definitely indicating an error. For the sake of completeness, I'd suggest you try the various other test .txt files and make sure you confidently get an off-by-one error )
Pages: 123