I want to read a text file in c++ using ifstream to know the number of words, characters, lines.
unsigned int wordNum = 0;
unsigned int lineNum = 0;
unsigned int charNum = 0;
char check;
ifstream in("example_2_4.txt");
char temp[30];
if (!in.is_open()) {
cout << "File opening error!" << endl;
}
while (!in.eof()){
in.getline(temp, 30);
wordNum += countWord(temp);
charNum += countChar(temp);
lineNum++;
in.clear();
}
The problem is that eof() does not work since there exists a line that exceeds 30 characters.
I've changed !in.eof() to in>>check and it works well but it reads a character so I can't count all characters in line.
I shouldn't use string class and can't change buffer size.
Is there any proper way to check eof?
I'm not entirely sure what you are asking, but ifstream::getline() sets the failbit when it tries to read a string that's too long. In your case, the eof bit will never be set (even though you are clearing all the bits anyway).
You can simply do:
while (in)
and in addition to not clearing any of the flags.
If you want to be able to read a line that is longer than the buffer you can store it in, you need to read the file some other way, perhaps using ifstream::get() instead.
in.getline(temp, 30); returns istream& so moving it in the while loop to here while(in.getline(temp, 30)) will return false when it reaches the end of file or a read error.
Try this:
string line;
ifstream myfile ("example_2_4.txt");
if (myfile.is_open())
{
while ( getline (myfile,line) )
{
cout << line << '\n';
wordNum += countWord(line);
charNum += countChar(line);
lineNum++;
}
myfile.close();
}
else cout << "Unable to open file";
return 0;
Given your constraints, I would suggest:
Read the file character by character.
End the loop when the EOF is reached.
Increment the number of characters.
Check whether the character marks the end of a word. If so, increment the word cound.
Check whether the character is a newline. If so, increment the number of lines.
int c;
while ( (c = in.get()) != EOF )
{
++charNum;
if (isspace(c) )
{
++wordNum;
}
if ( c == '\n' )
{
++lineNum;
}
}
Related
I am working on reading in from a file and parsing through data from command line argument for homework. And I ran in a wall and I do not know what's the problem, and I hope I could get some advice on what I am missing.
The data file is composed thusly; on the first line, it has number of total lines. For each line after that, it is a line of string separated by | character. I need the '|' character because I want to split my string into substrings.
Here is an example of input file.
3
league of legends|Teemo|Master Yi|Vayne
apple|samsung|smart phone|smart watch
overwatch|d.va|junkrat|Reinhart
Here is my code.
int main( int argc, char* const argv[] )
{
//change string to char* so I can check through each char to see if the
//thing I read in is '|' character.
String Data = (argv[1]);
ifstream fin (Data.c_str());
//check whether the file is open.
if ( !fin.is_open() )
{
cout << "Could not open file" << endl;
}
else
{
int dataLines;
char dataBuffer[100];
//The first integer I read in will be how many lines I will loop through
fin >> dataLines;
//ignore the new line character and do not include it in the count of
//dataLines.
fin.ignore();
//use noskipws so I can recognize whitespaces.
fin >> noskipws >> dataBuffer;
//TEST CODE: COMMENTED OUT FOR NOW.
//cout<<dataBuffer<<endl;
//loop for the number of lines
for(int i = 0; i < dataLines; i++)
{
fin.getline(dataBuffer, 100);
//print the buffer for checking
cout<<dataBuffer<<endl;
}
}
//close the file.
fin.close();
return 0;
}
The result is supposed to look like this.
league of legends|Teemo|Master Yi|Vayne
apple|samsung|smart phone|smart watch
overwatch|d.va|junkrat|Reinhart
The actual result looks like this
of legends|Teemo|Master Yi|Vayne
apple|samsung|smart phone|smart watch
overwatch|d.va|junkrat|Reinhart
The first word that I read in from buffer is gone. "league" is the one that is missing, and I tried to see what the problem is by inserting the test code at the location specified in my code. With the given test code, my output is
league
of legends|Teemo|Master Yi|Vayne
apple|samsung|smart phone|smart watch
overwatch|d.va|junkrat|Reinhart
So the problem is that between reading in the file with noskipws and the forloop that loops over dataLine. Before the forloop my buffer is league. Yet once I enter the loop it is passed that and goes straight to of.
What am I missing here? What could be a possible solution?
Main problem:
fin >> noskipws >> dataBuffer;
Does two things. 1. >> noskipws turns off automatically skipping whitespace, unnecessary because of how OP is reading the stream. 2. >> dataBuffer reads the first word from the stream, in this case consuming the word "league"
Solution: Don't do this.
Other problems:
fin.ignore();
will ignore exactly one character. But what if someone left a nigh-invisible space after the count? Instead use
fin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
to ensure the rest of the line is consumed in its entirity.
char dataBuffer[100];
Why make yourself suffer? Instead use
std::string dataBuffer;
Recommendation:
Use std::stringstream and std::getline to tokenize the lines on '|'
std::stringstream stream(databuffer);
std::string token;
while (std::getline(stream, token, '|')
{
std::cout << token << ',';
}
You do not need the following line:
fin >> noskipws >> dataBuffer;
Tested with g++ 4.8.3 2 on RHEL 7.1
Thanks User 4581301. It reads in the data correctly and split with '|' character. Now I can work on storing the data into classes.
for anyone who may have same problem, this is the fixed up version of code.
int main( int argc, char* const argv[] )
{
String Data = (argv[1]);
ifstream fin (Data.c_str());
if ( !fin.is_open() )
{
cout << "Could not open file" << endl;
}
else
{
int dataLines;
char dataBuffer[100];
fin >> dataLines;
fin.ignore();
for(int i = 0; i < dataLines; i++)
{
while(fin.getline(dataBuffer, 100, '|'))
{
cout<<dataBuffer<<endl;// check to see if it reads in correctly.
}
}
}
fin.close();
return 0;
}
I have created a file hangman_word_collection.txt and stored all the content of file into the string line.
Now I want to use the line string in my program but line[0] is not having any value into it or I don't know if it have something in it.
I am new to this please help.
Here is the code:
#include <iostream>
#include <fstream>
using namespace std;
int main() {
string line;
ifstream myfile ("hangman_word_collection.txt");
if (myfile.is_open()) {
while (myfile.good()) {
getline (myfile,line);
cout << line << endl;
}
}
for(int i=0; i <= 79; i++) {
cout << "\n" << i;
cout << ":" << line[i];
}
return 0;
}
And the output:
actingraringbackupcampusdacoiteasilyfabricgardenhackediceboxprimeralwaysupload.
0:
1:c
2:t
3:i
4:n
5:g
6:r
7:a
8:r
9:i
10:n
11:g
12:b
13:a
14:c
15:k
Press <RETURN> to close this window...
When getline fails on writing to your target line you are assuming it will not modify what is in that string but it is blanking the string, which internally is replacing character 0 with a null character.
The rest is undefined behaviour as you are reading characters off the end of the logical string.
To fix this issue change your code to;
string line;
ifstream myfile ("hangman_word_collection.txt");
if (myfile.is_open())
{
while (myfile.good())
{
std::string temp;
if( getline( myfile, temp ) )
{
temp.swap( line );
cout <<line<<endl;
}
}
}
Note that it is bad practice to hard-code in magic numbers like 79. If you had put line.size() instead you would have seen what size the string actually is, and there would be no undefined behaviour. You can store this in a variable outside the loop if you are worried about performance, although chances are it makes little difference.
I'm aware this has been asked a few time before and I read the threads related to it but the solutions there didn't work for me.
ifstream myFile;
myFile.open("largefile.txt");
if (myFile.is_open())
{
while (!myFile.eof( )) //step through each line until end of file
{
myFile>> str;
if(str.size() < 5){
amount++;
}
}
}
myFile.seekg(0, ios::beg);
if (myFile.is_open())
{
for(int i=0; i != random_integer; i++) //step through each line until random line reached
{
myFile>> str;
if(i == random_integer-1){
cout << "\n";
cout << str;
cout << "\n";
cout << str.size();
}
}
}
myFile.close();
I read that using EOF in the while statement was a bad idea, whats the alternative? And how can I rewind for the second loop as seekg isn't working out, I don't want to have to close the file and open again, and the file is to large to read into an array really?
TIA, I'm sure this is an easy fix I'm just very new to C++.
Instead of testing eof() (which doesn't work correctly), you should
just verify that each input has worked, by using the stream in a boolean
context:
while ( myFile >> str ) {
// ...
}
Once it has failed, of course, the stream is in a failed state, which
must be reset before any further operations are allowed:
myFile.clear();
myFile.seekg( 0, std::ios_base::beg );
myFile >> str is not guaranteed to work just because you checked for end of file, because that is a flag only set when EOF has been read, not when it is about to be read.
Instead you should do:
while( myFile >> str )
You also need to clear your stream before you use it again (with seekg). One of the unfortunate things about streams is that they hold state as flags and they can trip you up if you are not careful.
myFile.clear();
then continue.
Here is the code snippet:
int main()
{
char ch=26;
ofstream fout;
fout.open("key.txt");
if (fout.is_open())
{
for(int i=0; i<256; i++)
{
ch=i;
fout << ch;
cout<<ch;
}
fout.close();
}
else
cout << "Unable to open file";
string line;
ifstream fout1 ("key.txt");
if (fout1.is_open())
{
while (fout1)
{
fout1.get(ch);
cout <<" "<< (int)ch<<" "<<ch<<"\t ";
}
fout1.close();
}
else
cout << "Unable to open file";
return 0;
}
I found out that while reading 26th character it stops program. If it is escaped then all others are read. Note I am using Code Blocks IDE.
The reason why you can't read the 26th character is because its value is 26. And that is interpreted in textfiles as an end-of-file marker. You must open your file as binary ,then it will work.
In the code shown, I suggest you close the output file first, before opening it for reading. This will make sure that any characters in the buffer is flushed to disk. Also, after reading you might want to flush cout as well, if the program doesn't end there.
Also note that some characters are not printable, or do weird things when printed (like jumping to the beginning of the line, or deleting whats already being printed).
I am creating a program (In C++) that takes an ASCII file and reads a few values from each line until it reaches the end of the file. I am using ifstream to read the file, and I have never had problems with it stopping when I use the ifstream.eof() method. This time, however, even though it found the eof character in my test case, when I analyzed my other files, it is infinite looping because it never finds the eof character. Is this a coding issue, or an issue with my files?
string line = "";
unsigned long pos = 0;
ifstream curfile(input.c_str());
getline(curfile, line);
int linenumber = 0;
cout<<"About to try to read the file"<<endl;
if (!curfile.good())
cout<<"Bad file read"<<endl;
while (!curfile.eof())
{
cout<<"Getting line "<<linenumber<<endl;
linenumber++;
pos = line.find_first_of(' ');
line = line.substr(pos+1, line.size()-1);
pos = line.find_first_of(' ');
current.push_back(atof(line.substr(0, pos).c_str()));
for (int i = 0; i<4; i++)
{
pos = line.find_first_of(' ');
line = line.substr(pos+1, line.size()-1);
}
pos = line.find_first_of(' ');
dx.push_back(atof(line.substr(0, pos).c_str()));
pos = line.find_first_of(' ');
line = line.substr(pos+1, line.size()-1);
pos = line.find_first_of(' ');
dy.push_back(atof(line.substr(0, pos).c_str()));
getline(curfile, line);
}
EDIT: When I first run the loop, currentfile.good() returns false...what am I doing that causes it to return that?
First thing is first, you shouldn't check like that. eof() doesn't return true until after a failed read. But you can do better (and easier)!
check the stream state with the implicit conversion to void* which can be used in a bool context. Since most of the read operations on streams return a reference to the stream, you can write some very consice code like this:
std::string line;
while(std::getline(currentfile, line)) {
// process line
}
Basically what it is doing is saying "while I could successfully extract a line from currentfile, do the following", which is what you really meant to say anyway ;-);
Like I said, this applies to most stream operations, so you can do things like this:
int x;
std::string y;
if(std::cin >> x >> y) {
// successfully read an integer and a string from cin!
}
EDIT: The way I would rewrite your code is like this:
string line;
unsigned long pos = 0;
int linenumber = 0;
ifstream curfile(input.c_str());
std::cout << "About to try to read the file" << std::endl;
while (std::getline(curfile, line)) {
std::cout << "Getting line " << linenumber << std::endl;
linenumber++;
// do the rest of the work with line
}
Do not do it like that.
EOF is not the only thing you'll encounter while reading. There's a bunch of errors you might get, and so the best is to simply test the stream itself:
while(currentfile)
{
// read somehow
}
If you're reading lines, then, the simplest way is:
std::string line;
while(std::getline(currentfile, line))
{
// use line
}
Your first call to getline is triggering one of the fail-bits on the ifstream object. That is why if you do a check for a fail-bit using ios::good(), you never enter your read loop. I would check to see what the value of line is ... it's probably empty, meaning you're having another issue reading your file, like maybe permissions problems, etc.
The problem is here:
if (!curfile.good())
cout<<"Bad file read"<<endl; // OK you print bad.
while (!curfile.eof()) // But the loop is still entered.
// Another reason to **NEVER** to use
// while (file.eof()) // as bad does not mean eof
// though eof is bad
Try this:
void readFile(std::istream& str)
{
std::string line;
while(std::getline(str, line))
{
std::stringstream lineStream(line);
std::string ignoreWord;
int number[3];
lineStream >> ignoreWord // reads one space seporated word
>> number[0] // reads a number
>> ignoreWord >> ignoreWord >> ignoreWords // reads three words
>> number[1] // reads a number
>> number[2]; // reads a number
current.push_back(number[0]);
dx.push_back(number[1]);
dy.push_back(number[2]);
}
}