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.
Related
I am new in C++. This is a part of a program that actually runs, no mem-leak. It reads a line counting how much doubles per/line there are (aux_d), and if it is equal to dim (dimention) it push_back into the vector.
Read line, and then rewind istringstream fss. But when i print my v_db[i] (vector_database) it only loads zeros into the coordinate class.
coordinates aux_c;
double aux_d;
... do stuff and then
while(std::getline(filestream,line)){
i=0;
std::istringstream fss(line);
while( fss >> aux_d )
i++;
if (i != dim){
std::cerr << "Wrong Tiberium_Base coordinates // "
<< "Check line -"
<< lc
<< "-"
<< std::endl;
lc++;
continue;
}
fss.seekg(0);
fss >> aux_c;
v_db.push_back(aux_c);
lc++;
}
So i did this just to make it work.
std::istringstream fss2(line);
fss2 >> aux_c;
v_db.push_back(aux_c);
lc++;
I would like to know what the heck is going on here, since i've used seekg with that same purpose before, and didnt have any problem at all (in this program actually). Thanks.
After you are finished with the loop.
while( fss >> aux_d )
i++;
fss has failbit set. You need to clear that before you can use the stream.
while( fss >> aux_d )
i++;
...
// Clear the error states of the stream.
fss.clear();
fss.seekg(0);
fss >> aux_c;
I'm trying to write a program that replaces a specific number with an 'x' character. The task requires every number to be in its own line, but it seems like '\n' is causing the read/write pointers to behave out of this world. Here's a picture of the output.
My questions are:
why are the pointers behaving this way?
How far do I need to move the write pointer backwards to overwrite a line to make this work?
is there an easier workaround?
Here's my code:
void input(int n)
{
fstream file;
file.open("numbers.txt", ios::out);
while(n --> 0)
{
file << n;
file << '\n';
}
file.close();
}
void read()
{
fstream file;
string tmp;
file.open("numbers.txt", ios::in);
while(true)
{
getline(file,tmp);
if(file.eof())
break;
cout << tmp << endl;
cout << "tellg: " << file.tellg() << " tellp: " << file.tellp() << endl;
}
file.close();
}
void replace()
{
fstream file;
string tmp;
file.open("numbers.txt", ios::in | ios::out);
while(true)
{
file >> tmp;
if(tmp == "6")
{
//cout << file.tellg() << endl;
file.seekp(file.tellg() - tmp.length()-1);
file << "x";
}
if(file.eof())
break;
}
file.close();
}
int main()
{
input(10);
replace();
read();
return 0;
}
Since you open your file in text mode, you need to account for the potential that the underlying stream may use a line end sequence (\r\n) rather than just a \n. I guess, this is the primary problem. The easiest remedy is probaly to open the file in binary mode:
file.open("numbers.txt", std::ios_base::binary | std::ios_base::in | std::ios_base::out);
That said, since you switch from writing to reading without intervening seek, your code is undefined behavior, i.e., anything can happen. You should seek to the current location between writing and reading.
Personally, I'd refrain from rewriting files in-place. It generally gets unnecessary trick. If I were to rewrite files in place, I'd use seekg() to get the current position before a read, saving the position and restoring it prior to the write (I essentially never use the seek operations, i.e., I may have got the signatures wrong):
for (std::streampos pos = (in >> std::ws).tellg();
in >> tmp; pos = (in >> ws).tellg()) {
if (need_to_overwrite) {
in.seekp(pos);
// ...
in.seekg(0, std::ios_base::cur);
}
}
The use of in >> std::ws is to make sure that whitespace is skipped before storing the position.
Also note that your check for file.eof() is wrong: the last line is processed twice. When reading from a file the result shall be tested before using the read string, e.g.:
while (in >> tmp) {
// ...
}
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;
}
}
I have a file that has a number in which is the number of names that follow. For example:
4
bob
jim
bar
ted
im trying to write a program to read these names.
void process_file(ifstream& in, ofstream& out)
{
string i,o;
int tmp1,sp;
char tmp2;
prompt_user(i,o);
in.open (i.c_str());
if (in.fail())
{
cout << "Error opening " << i << endl;
exit(1);
}
out.open(o.c_str());
in >> tmp1;
sp=tmp1;
do
{
in.get(tmp2);
} while (tmp2 != '\n');
in.close();
out.close();
cout<< sp;
}
So far I am able to read the first line and assign int to sp
I need sp to be a counter for how many names. How do I get this to read the names.
The only problem I have left is how to get the names while ignoring the first number.
Until then i cannot implement my loop.
while (in >> tmp1)
sp=tmp1;
This successfuly reads the first int from the and then tries to continue. Since the second line is not an int, extraction fails, so it stops looping. So far so good.
However, the stream is now in fail state, and all subsequent extractions will fail unless you clear the error flags.
Say in.clear() right after the first while loop.
I don't really see why you wrote a loop to extract a single integer, though. You could just write
if (!(in >> sp)) { /* error, no int */ }
To read the names, read in strings. A loop is fine this time:
std::vector<std::string> names;
std::string temp;
while (in >> temp) names.push_back(temp);
You'd might want to add a counter somewhere to make sure that the number of names matches the number you've read from the file.
int lines;
string line;
inputfile.open("names.txt");
lines << inputfile;
for(i=0; i< lines; ++i){
if (std::getline(inputfile, line) != 0){
cout << line << std::endl;
}
}
First of all, assuming that the first loop:
while (in >> tmp1)
sp=tmp1;
Is meant to read the number in the beginning, this code should do:
in >> tmp1;
According to manual operator>>:
The istream object (*this).
The extracted value or sequence is not returned, but directly stored
in the variable passed as argument.
So don't use it in condition, rather use:
in >> tmp1;
if( tmp1 < 1){
exit(5);
}
Second, NEVER rely on assumption that the file is correctly formatted:
do {
in.get(tmp2);
cout << tmp2 << endl;
} while ( (tmp2 != '\n') && !in.eof());
Although whole algorithm seems a bit clumsy to me, this should prevent infinite loop.
Here's a simple example of how to read a specified number of words from a text file in the way you want.
#include <string>
#include <iostream>
#include <fstream>
void process_file() {
// Get file name.
std::string fileName;
std::cin >> fileName;
// Open file for read access.
std::ifstream input(fileName);
// Check if file exists.
if (!input) {
return EXIT_FAILURE;
}
// Get number of names.
int count = 0;
input >> count;
// Get names and print to cout.
std::string token;
for (int i = 0; i < count; ++i) {
input >> token;
std::cout << token;
}
}
If I include the if test in my code the error message is returned and I'm not sure why.
and when it's not used, my program get's stuck in a loop where it never reaches the end of the file. I don't understand what's going wrong.
int countlines()
{
fstream myfile;
myfile.open("questions.txt", ios::in);
string contents;
int linenumber = 0;
//if (myfile.is_open())
// {
while (!myfile.eof())
{
getline( myfile, contents );
if (contents != "")
{
linenumber++;
}
}
cout << "there are " << linenumber << " lines.\n";
//}else {cout<<"Unable to get file.\n";}
myfile.close();
return(linenumber);
}
What's going on is that your file is not being opened. That's why is_open fails.
Then, when you comment out the check, you're breaking your loop because you're iterating incorrectly (see my comment) and not detecting stream failures (.eof() will never be true on that stream).
Make sure that the file is in the right place, and that it is accessible.
The correct idiom for reading a file line-by-line in C++ is using a loop like this:
for (std::string line; std::getline(file,line);)
{
// process line.
}
Inserting this in your example (+fixing indentation and variable names) gives something like this:
int countlines(const std::string& path)
{
// Open the file.
std::ifstream file(path.c_str());
if (!file.is_open()) {
return -1; // or better, throw exception.
}
// Count the lines.
int count = 0;
for (std::string line; std::getline(file,line);)
{
if (!line.empty()) {
++count;
}
}
return count;
}
Note that if you don't intend to process the line contents, you can actually skip processing them using std::streambuf_iterator, which can make your code look like:
int countlines(const std::string& path)
{
// Open the file.
std::ifstream file(path.c_str());
if (!file.is_open()) {
return -1; // or better, throw exception.
}
// Refer to the beginning and end of the file with
// iterators that process the file character by character.
std::istreambuf_iterator<char> current(file);
const std::istreambuf_iterator<char> end;
// Count the number of newline characters.
return std::count(current, end, '\n');
}
The second version will completely bypass copying the file contents and avoid allocating large chunks of memory for long lines.
When using std::istream and std::ostream (whose std::fstream implements), the recommended usage is to directly use the stream in a bool context instead of calling eof() function because it only return true when you managed to read until the last byte of the file. If there was any error before that, the function will still return true.
So, you should have written your code as:
int countlines() {
ifstream myfile;
int linenumber = 0;
string linecontent;
myfile.open("question.txt", ios::in);
while (getline(myfile, linecontent)) {
if (!linecontent.empty()) {
++linenumber;
}
}
return linenumber;
}
Try the following code. It will also (hopefully) give you an idea why the file open is failing...
int countlines()
{
ifstream myfile;
myfile.open("questions.txt");
string contents;
int linenumber = 0;
if (myfile.is_open())
{
while (getline(myfile, contents))
{
if (contents != "")
linenumber++;
}
cout << "there are " << linenumber << " lines." << endl;
myfile.close();
}
else
cout << "Unable to get file (reason: " << strerror(errno) << ")." << endl;
return linenumber;
}