problems with seekg after getlines[which exhausts file] on ifstream - c++

I am trying to write a program to print last line of file, and I came up with following. Where I am doing SEEKs in the file, but this code runs in an infinite loop. If I comment out (1) and enable (2), code works fine. I wasn't able to figure out the reason.
#include <iostream>
#include <fstream>
int main()
{
std::string line;
int count = 0;
long int seek_length = -1l;// should be -100l
std::ifstream ifile("D:\\cprog\\test.csv");// --(1)
while(true){
seek_length *= 2;
count = 0;
//std::ifstream ifile("D:\\cprog\\test.csv"); //-- (2)
ifile.seekg(seek_length, std::ios_base::end);
while(std::getline(ifile,line)){
++count;
}
if(count > 1)
break;
}
std::cout << line << '\n';
}
Compiler: g++ (GCC) 4.9.2 (MINGW)

You need to clear the error state on your stream before reading again:
ifile.clear();
Otherwise, the first time it encounters EOF, the stream gets into an error state and all subsequent reads will fail.
Beware that if you do this and your file only contains 1 (or 0) lines, your code in its present form will loop forever.

Final working code is following, the problem can be solved in one of the following ways.
#include <iostream>
#include <fstream>
int main()
{
std::string line;
int count = 0;
long int seek_length = -100l;
std::ifstream ifile("D:\\cprog\\test.csv");
#if 0
while(true){
seek_length *= 2;
count = 0;
ifile.seekg(seek_length, std::ios_base::end);
if( ifile.tellg() < 0 ){
ifile.clear();
ifile.seekg(0l, std::ios_base::beg);
while(std::getline(ifile,line));
break;
}
else
{
while(std::getline(ifile,line)){
++count;
}
if(count > 1)
break;
}
ifile.clear();
}
#else
char ch;
ifile.seekg(0l, std::ios_base::end);
do
{
ch = ifile.peek();
ifile.seekg(-1l, std::ios_base::cur);
std::cout << ch <<'~' << ifile.tellg() <<'\n';
}while(ch != '\n' && ifile.tellg() > -1 );
if(ifile.tellg() < 0 )
ifile.seekg(0l, std::ios_base::beg);
else
ifile.seekg(2l, std::ios_base::cur);
ifile.clear();
std::getline(ifile,line);
#endif
if(line.empty())
std::cout<<"------- EMPTY LINE -----\n";
else std::cout << line << '\n';
}

Related

File for loop doesn't open file c++

This file is not opening for a reason which I don't know really, any insight?
#include <iostream>
#include <string>
#include <algorithm>
#include <fstream>
#include <cctype>
using namespace std;
.
.
.
.
.
void MinHeap::TopKFrequentWord(string fileName, int k)
{
MinHeap mh;
Trie T;
string word;
string line;
ifstream inFile(fileName);
for (int i = 0; i < 22; i++)
{
if (i >= 10)
{
fileName = "C:\\Users\\Kareem's Laptop\\Desktop\\Reuters-21578\\reut2-0" + to_string(i) + ".sgm";
}
else if (i <= 9)
{
fileName = "C:\\Users\\Kareem's Laptop\\Desktop\\Reuters-21578\\reut2-00" + to_string(i) + ".sgm";
}
if (!inFile)
{
cout << fileName << " did not open." << endl;
exit(1);
}
bool found = true;
while (inFile >> line)
{
size_t pos = line.find("<BODY>");
if (pos != string::npos)
{
if (found)
{
word = line.substr(pos + 6);
found = true;
TrieNode* TN = T.search(word);
if (!TN)
{
TN = T.insert(word);
}
else
{
TN->frequency++;
}
mh.insert(TN, word);
}
}
}
mh.Display();
cout << '\n';
inFile.close();
}
}
int main()
{
MinHeap foo;
string fileName;
foo.TopKFrequentWord(fileName, 10);
return 0;
}
I have to open 21 files in a loop, read them all and print out the top 10 word count for all of those words.
Unable to use vector due to instructions. I apologize if similarities are obvious.
I tried putting all files in an array but it still didn't work. No errors just not opening (getting exit(1) command).
You are opening the file before the loop. Since you are updating the filename variable inside the loop, I suppose you want to open it each time you pass through the loop.
Move the line :
ifstream inFile(fileName);
to one line before the test:
if (!inFile)
Also, the place where you code ifstream inFile(fileName); you have an empty string in fileName (You didn't initialize the variable passed as argument in main).
Also, you are passing a int k parameter to the function but never uses it there.

Ignoring certain lines in a txt file when parsing

I want to read files from a txt file and compare some lines with regex.
The first line of the txt file should start with the string #FIRST.
And if the string should start with a '#' the line should be ignored and it should continue. So counter should have the value 1 which it does and it should go to the second if statement if(counter==1). However it doesn't go to the second if statement.
txt file:
#FIRST
#
#haha
I expect the output to be good\ngood after the code is run once.
The output is:
good.
And it should be
good.
good.
.........
#include <iostream>
#include <string>
#include <vector>
#include <regex>
#include <fstream>
#include <sstream>
int main() {
std::ifstream input("test.txt");
std::regex e("#FIRST");
std::regex b("haha");
int counter;
for (counter = 0; !input.eof(); counter++) {
std::cout << counter << "\n";
std::string line;
if (counter == 0) {
getline(input, line);
if (std::regex_match(line, e)) {
std::cout << "good." << std::endl;
counter++;
} else
std::cout << "bad." << std::endl;
break;
}
getline(input, line);
if (line[0] == '#')
continue;
if (counter == 1) {
getline(input, line);
if (std::regex_match(line, b)) {
std::cout << "good." << std::endl;
} else
std::cout << "bad." << std::endl;
break;
}
}
return 0;
}
The issue is with the break statement in the first if clause. After getting the first line of the input the program encounters the break statement and breaks out of the loop immediately. No further statements are executed within the for loop which I believe is the behavior you are seeing. You will have to restructure the program to be something like:
for loop {
getline()
if (counter == <>) {
// no break
} else if (line[0] == '#') {
continue;
} else {
// whatever else you want to get done
}
}

Why isn't a string vector value converted to cstring the equivalent of manually writing the string?

I have an input file that contains a list of .txt files in a folder. I loop through the input file just fine and put the .txt file filepaths in string vectors. However, when I try to open another ifstream using one of the filepaths in the sections vector (string vector value converted to cstring),
std::ifstream secFile(sections[i].c_str());
The line secFile.fail() returns true meaning it fails. If I instead use the currently commented out line that hardcodes a filepath (manually writing the string) rather than getting it from a vector,
//std::ifstream secFile("test2/main0.txt");
it no longer fails. I even tried outputting sections[0].c_str() and "test2/main0.txt" to a text file and the text for each is exactly the same. I even compared the hexadecimal values for the text file and there were no invisible characters that might cause such an issue.
Any idea what the problem might be?
Here is my code:
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <cstring>
//using namespace std;
int main (int argc, char* argv[]){
if(argc != 2){
return(0);
}
std::vector<std::string> sections;
std::vector<std::string> overlaps;
std::ifstream file(argv[1]);
std::string str;
std::string secLine;
std::string overlapLine;
std::string strLow;
std::string wholePage = "";
//determine if input text file is overlap text or main text
while (getline(file, str))
{
if (str.find("overlap")!=-1){
overlaps.push_back(str);
}
else{
sections.push_back(str);
}
}
file.clear();
for(int i = 0; i < sections.size();i++){
//HERE IS MY QUESTION
std::ifstream secFile(sections[i].c_str());
//std::ifstream secFile("test2/main0.txt");
if(secFile.good()){
std::cout << "\ngood4\n";
}
if(secFile.bad()){
std::cout << "bad4\n";
}
if(secFile.fail()){
std::cout << "fail4\n";
}
if(secFile.eof()){
std::cout << "eof4\n";
}
int secLength = 0;
//determine number of files in test2/
while (getline(secFile,secLine)){
secLength++;
}
secfile.clear();
secfile.seekg(0);
int j = 0;
while (getline(secFile,secLine)){
if (i == 0 && j==0){
wholePage += std::string(secLine) + "\n";
}
else if(j==0){
//do nothing
}
else if(i == (sections.size()-1) && j == secLength){
wholePage += std::string(secLine) + "\n";
}
else if(j == secLength){
//do nothing
}
else{
wholePage += std::string(secLine) + "\n";
}
j++;
}
int k = 0;
if(i < sections.size()-1){
std::ifstream overFile(overlaps[i].c_str());
int overLength = 0;
while (getline(overFile,overlapLine)){
overLength++;
}
while (getline(overFile,overlapLine)){
std::cout << "Hi5";
if(k == 0){
//do nothing
}
else if(k == overLength){
//do nothing
}
else{
if (wholePage.find(overlapLine)){
//do nothing
}
else{
wholePage += std::string(secLine) + "\n";
}
}
}
k++;
}
}
std::ofstream out("output.txt");
out << wholePage;
out.close();
std::cout << "\n";
return 0;
}
You haven't provided enough information to be sure, but the most likely problem is whitespace. getline doesn't strip the trailing whitespace from the lines it produces, so you might be trying to open a file named "test2/main0.txt " (trailing space), which is distinct from "test2/main0.txt". You'll want to trim trailing whitespace in most cases, likely before storing the string to your vector. Since some whitespace can legally be part of a filename, the real solution would be to make sure the garbage whitespace isn't there, but trailing whitespace is filenames is rare enough that you could just hope the file names don't use it.
Here you are passing a filename:
std::ifstream secFile("test2/main0.txt");
Here you are passing a line of text from a file:
std::ifstream secFile(sections[i].c_str());
ifstream expects a filename, not a line of text from a file. It is failing because the text you are inputting doesn't represent a file you are trying to open.

how to count the characters in a text file

im trying to count the characters inside a text file in c++, this is what i have so far, for some reason im getting 4. even thou i have 123456 characters in it. if i increase or decrease the characters i still get 4, please help and thanks in advance
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
const char FileName[] = "text.txt";
int main ()
{
string line;
ifstream inMyStream (FileName);
int c;
if (inMyStream.is_open())
{
while( getline (inMyStream, line)){
cout<<line<<endl;
c++;
}
}
inMyStream.close();
system("pause");
return 0;
}
You're counting the lines.
You should count the characters. change it to:
while( getline ( inMyStream, line ) )
{
cout << line << endl;
c += line.length();
}
There are probably hundreds of ways to do that.
I believe the most efficient is:
inMyStream.seekg(0,std::ios_base::end);
std::ios_base::streampos end_pos = inMyStream.tellg();
return end_pos;
First of all, you have to init a local var, this means:
int c = 0;
instead of
int c;
I think the old and easy to understand way is to use the get() function till the end char EOF
char current_char;
if (inMyStream.is_open())
{
while(inMyStream.get(current_char)){
if(current_char == EOF)
{
break;
}
c++;
}
}
Then c will be the count of the characters
this is how i would approach the problem:
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main ()
{
string line;
int sum=0;
ifstream inData ;
inData.open("countletters.txt");
while(!inData.eof())
{
getline(inData,line);
int numofChars= line.length();
for (unsigned int n = 0; n<line.length();n++)
{
if (line.at(n) == ' ')
{
numofChars--;
}
}
sum=numofChars+sum;
}
cout << "Number of characters: "<< sum << endl;
return 0 ;
}
Just use good old C FILE pointers:
int fileLen(std::string fileName)
{
FILE *f = fopen(fileName.c_str(), "rb");
if (f == NULL || ferror(f))
{
if (f)
fclose(f);
return -1;
}
fseek(f, 0, SEEK_END);
int len = fell(f);
fclose(f);
return len;
}
I found out this simple method , hope this helps
while(1)
{
if(txtFile.peek() == -1)
break;
c = txtFile.get();
if(c != txtFile.eof())
noOfChars++;
}
This works for sure, it is designed to read character by character.
It could be easily put into a class and you may apply function for every char, so you may check for '\n', ' ' and so on. Just have some members in your class, where they can be saved, so you may only return 0 and use methods to get what exactly you want.
#include <iostream>
#include <fstream>
#include <string>
unsigned long int count(std::string string)
{
char c;
unsigned long int cc = 0;
std::ifstream FILE;
FILE.open(string);
if (!FILE.fail())
{
while (1)
{
FILE.get(c);
if (FILE.eof()) break;
cc++; //or apply a function to work with this char..eg: analyze(c);
}
FILE.close();
}
else
{
std::cout << "Counter: Failed to open file: " << string << std::endl;
}
return cc;
};
int main()
{
std::cout << count("C:/test/ovecky.txt") << std::endl;
for (;;);
return 0;
}
C++ provides you with a simple set of functions you can use to retrieve the size of stream segment.
In your case, we want to find the file end, which can be done by using fstream::seekg, and providing the fstream::end.
note that fstream is not implementing the end iterator overload, this is it's own end constant
When we've seeked towards the end of the file, we want to get the position of the stream pointer, using tellg (also known as the character count in our case).
But we're not done yet. We need to also set the stream pointer to its original position, otherwise we'll be reading from the end of the file. Something we don't want to do.
So lets call fstream::seekg again, but this time set the position to the begining of the file using fstream::beg
std::ifstream stream(filepath);
//Seek to end of opened file
stream.seekg(0, stream.end);
int size = stream.tellg();
//reset file pointer to the beginning of the file
stream.seekg(0, stream.beg);

Why doesn't this code run?

Hey, sorry if this is asked a lot but I have no idea what the problem here is.
In the C++ code below, I'm reading from a user defined input file and generating output. I've been writing it piece by piece and putting it together, compiling, testing, etc as I go to work out the bugs. This is a learning experience for me, first self-directed program I guess...
Anyways, when I run the code, the command prompt prints ONE line and goes unresponsive. I would say it has been caught in some kind of loop, but I believe that's impossible.
I think it might have something to do with the array I'm trying to declare, I wanted to make a dynamic string array but I found out that's difficult...
#include <iostream>
#include <fstream>
#include <algorithm>
#include <cctype>
#include <string>
using namespace std;
int wordCount(string line)
{
int fpos, fpos2;
int count = 0;
fpos = line.find_first_not_of(' ');
line.erase(0, fpos);
while(line.size() > 0)
{
fpos = line.find_first_of(' ');
if(line.at(0) == '"')
{
line.erase(0, 1);
for(int i = 0; i <line.size(); i++)
if(line.at(i) == '"' && line.at(i-1) != '\\')
{
fpos2 = i;
break;
}
line.erase(0, fpos2 + 2);
}
else
line.erase(0, fpos + 1);
count++;
}
return count;
}
int main()
{
//Current line; Input file; Output file;
string currentline, fileName, outFileName;
ifstream fin;
ofstream fout;
cout << "Enter input file name: ";
getline(cin, fileName);
cout << "Enter output file name: ";
getline(cin, outFileName);
fin.open(fileName.c_str());
if (!fin.good()) throw "I/O error";
fout.open(outFileName.c_str());
if (!fout.good()) throw "I/O error";
getline(fin, currentline);
while (!currentline.empty())
{
int pos, pos1;
pos = currentline.find("//");
string postScript = currentline.substr(pos+2,-1);
pos = currentline.find_first_of(';');
string xline = currentline.substr(0,pos+1);
cout << xline << endl;
int size = wordCount(xline);
string *words;
words = (string *) malloc (size*sizeof(string));
words = new string[size];
pos = xline.find_first_not_of(' ');
xline.erase(0, pos);
for ( int i = 0; i < size; i++ )
{
pos = xline.find_first_of(' ');
if ( xline.at(0) == '"' )
{
xline.erase(0, 1);
for(int a = 0; a < xline.size(); a++) //This for loop finds the end of a quoted statement within the line.
if ( xline.at(a) == '"' && xline.at(a-1) != '\\' )
{
pos = a;
break;
}
words[i] = xline.substr(0,pos);
xline.erase(0,pos + 2);
}
else
{
words[i] = xline.substr(0,pos);
xline.erase(0,pos + 1);
}
cout << words[i] << endl;
}
cout << xline << endl << endl;
getline(fin, currentline);
}
return 0;
}
I would suggest you commenting out bits of code until it starts to work the way you expect (Usually the problematic bit will become obvious this way.) Once you figure out what is wrong you can ask a more specific question on StackOverflow.
You should use a debugger to investigate the program behavior.
To avoid single stepping the whole program, you can set breakpoints where you expect to passs the sequence. When a breakpoint is not hit you can use single stepping from the previous point. Additionally you can look at variables content.
It never finds the end quote:
if ( xline.at(a) == '"' && xline.at(a-1) != '\\' )
{
pos = a;
break;
}
Try this instead:
if (xline.at(a) == '"')
{
pos = a;
break;
}
You only need to escape " if its contained in a string literal, e.g. "There's a \" in this literal"