Reading specific lines from a file in C++ - c++

The following code is meant to loop through the last ten lines of a file that I have previously opened. I think the seekg function refers to binary files and only go through individual bytes of data, so that may be my issue here.
//Set cursor to 10 places before end
//Read lines of input
input.seekg(10L, ios::end);
getline(input, a);
while (input) {
cout << a << endl;
getline(input, a);
}
input.close();
int b;
cin >> b;
return 0;
}
The other method I was thinking of doing is just counting the number of times the file gets looped through initially, taking that and subtracting ten, then counting through the file that number of times, then outputting the next ten, but that seems extensive for what I want to do.
Is there something like seekg that will go to a specific line in the text file? Or should I use the method I proposed above?
EDIT: I answered my own question: the looping thing was like 6 more lines of code.

Search backwards for the newline character 10 times or until the file cursor is less than or equal to zero.

If you don't care about the order of the last 10 lines, you can do this:
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <cmath>
int main() {
std::ifstream file("test.txt");
std::vector<std::string> lines(10);
for ( int i = 0; getline(file, lines[i % 10]); ++i );
return 0;
}

Related

In C++ why is ifstream getline returning every other number in my .txt file, rather than all of them?

When I run this code it doesn't print the contents of the .txt file which is numbers 1 to 100, it prints all of the even numbers up to 100 (e.g. 2 4 6 8 so on.) And I don't know why, it didn't before and I don't think I changed anything. I'm using xcode. Anybody got any ideas?
#include <stdio.h>
#include <iostream>
#include <cmath>
#include <string>
#include <sstream>
#include <fstream>
using namespace std;
int main () {
string line;
int Points[100];
ifstream myfile("StatNum.txt");
if (myfile.is_open())
{
while ( getline (myfile,line) )
{
getline(myfile,line);
stringstream(line) >> Points[100]; //uses stringstream to convert Myline (which is a string) into a number and put it into an index of Points
cout << Points[100] << endl;
}
myfile.close();
}
else cout << "Unable to open file" << endl;
return 0;
}
This happens because you call getline twice per iteration:
First, you call it in the while header
Then you call it inside the loop.
One invocation (the one in the while header) is sufficient, because the result is saved in the line variable, which the loop body is free to examine.
Removing the second invocation will fix the problem.
As #dasblinkenlight pointed out, you are calling std::getline() twice and that's the problem that you see.
The problem that you can't see is that you are writing data to Points[100] which is an invalid location, outside of the array's bounds. The 100 valid locations in your array are indexes 0 to 99, that is Points[0], Points[1], ..., Points[99] (because counting in C++ starts from 0, not 1).
Writing to Points[100] is Undefined Behavior which means that your program may crash, or worse: may not crash while corrupting its own data.
Since you're using C++ you have std::vector and other containers at your disposal, where you can easily store the numbers you read:
#include <vector>
// ...
vector<int> points;
while (getline(myfile, line))
{
int temp;
stringstream(line) >> temp;
points.push_back(temp);
cout << temp << endl;
}

Trying to open file using fstream but it is not working

I am trying to run this but the file is constantly failing to load. What I am trying to do is load a dictionary into an Array with each level of an array accounting for one word.
#include <iostream>
#include <string>
#include <fstream>>
#include <time.h>
#include <stdlib.h>
using namespace std;
int Rand;
void SetDictionary(){
srand(time(NULL));
Rand = rand() % 235674;
fstream file("Hangman.txt");
if(file.is_open()){
string Array[235675];
for(int X = 0; X < 235673; X++){
file >> Array[X];
}
cout << Array[Rand];
}else{
cout << "Unable To Open File\n";
}
}
int main(){
SetDictionary();
}
vector<string> words;
{
ifstream file("Hangman.txt");
string word;
while (file >> word)
{
words.push_back(word);
}
}
string randword = words[rand() % words.size()];
At first, I see you do not reuse Array after cout << Array[Rand] is done. You do not need array at all in this case. Read the file line by line into temp variable and cout this variable if condition X==Rand, then break.
At second, the implementation could be improved. Assumed you are trying to cout random word from file. It would be 1000-times faster to generate Rand as 0..file-size, then offset to this Rand. Now you are "inside" desired word and the task is to read back and forward for the work begin and end respectively. This algorithm will show a bit different probability distribution.
At third. If you plan to reuse file data, it would be much faster to read whole file into memory, and then do split by words, storing words offsets as arrays of integers.
At last. With really huge dictionaries (or if the program run on limited memory) it is possible to store words offsets only, and re-read dictionary contents on-the-fly.

Counting alphanumeric characters in a text file in C++

I wrote a program for counting the number of alphanumeric characters in a text file. However, the number it returns is always larger than the number that online character counters return.
For example, the program will calculate the number of alphanumeric characters in this text:
if these people had strange fads and expected obedience on the most
extraordinary matters they were at least ready to pay for their
eccentricity
to be 162. Running the program again, it'll say there are 164 characters in the text. Running it again, it'll say there are 156 characters. Using this online character counter, it seems that the character count ought to be lower than 144 (the online character counter includes spaces as well).
Here is the code:
#include <iostream>
#include <fstream>
#include <cctype>
using namespace std;
int main() {
char line[100];
int charcount = 0;
ifstream file("pg1661sample.txt");
while (!file.eof()) {
file.getline(line, 99);
for (int i = 0; i < 100; i++) {
if (isalnum(line[i])) {
charcount++;
}
}
}
cout << endl << "Alphanumeric character count: " << charcount;
cin.get();
return 0;
}
What am I doing wrong?
Try:
#include <iterator>
#include <algorithm>
#include <iostream>
#include <cctype>
bool isAlphaNum(unsigned char x){return std::isalnum(x);}
int main()
{
std::cout << "Alphanumeric character count: " <<
std::count_if(std::istream_iterator<char>(std::cin),
std::istream_iterator<char>(),
isAlphaNum
) ;
}
Problems with your code:
EOF is not true until you read past the end of file:
// this is true even if there is nothing left to read.
// If fails the first time you read after there is nothing left.
while (!file.eof()) {
// thus this line may fail
file.getline(line, 99);
It is better to always do this:
while(file.getline(line, 99))
The loop is only entered if the getline actually worked.
You are also using a bad version of getline (as lines may be larger than 100 characters).
Try and use the version that works with std::string so it auto expands.
std::string line;
while(std::getline(file, line))
{
// stuff
}
Next you assume the line is exactly 100 characters.
What happedn if the line is only 2 characters long?
for (int i = 0; i < 100; i++)
Basically you will scan over the data and it will count letters that were from left over from a previous line (if a previous line was longer than the current) or completely random garbage. If you are still useing file.getline() then you can retrieve the number of characters from a line using file.gcount(). If you use the std::getline() then the variable line will be the exact size of the line read (line.size()).
while (!file.eof()) {
Don't do this. eof() doesn't return true until after an attempted input has failed, so loops like this run an extra time. Instead, do this:
while (!file.getline(line, 99)) {
The loop will terminate when the input ends.
The other problem is in the loop that counts characters. Ask yourself: how many characters got read into the buffer on each pass through the input loop? And why, then, is the counting loop looking at 100 characters?
You're assuming that getline() fills line with exactly 100 characters. Check the length of the string read in by getline(), e.g. using strlen():
for (int i = 0; i < strlen(line); i++) {
if (isalnum(line[i])) {
charcount++;
}
}
EDIT: Also, make sure you heed the suggestion from other answers to use getline()'s return value for the loop condition rather than calling eof().

fstream's getline() works for a little bit...and then breaks

I have a text file with a bunch of numbers separated by newlines, like this:
123.25
95.12
114.12 etc...
The problem is, when my program reads it, it only copies the number to the array up to the second number and then fills the rest of the elements with zeroes. I've tried using delimiters and ignore statements but nothing has worked. Here's the code.
Edit(here's the whole program:)
#include <iostream>
#include <string.h>
#include <iomanip>
#include <fstream>
using namespace std;
struct utilityInfo
{
char utility[20];
double monthlyExpenses[12];
};
int main(){
utilityInfo Utility[3];
char charray[100];
fstream inFile;
inFile.open("expenses.txt");
inFile.getline(charray, 7);
cout<<charray<<endl;
if(inFile.fail()) cout<<"it didnt work";
for(int i=0; i<12; i++)
{
inFile.getline(charray,20);
Utility[0].monthlyExpenses[i]=atof(charray);
}
for(int z=0; z<12; z++)
{
cout<<Utility[0].monthlyExpenses[z]<<endl;
}
inFile.close();
return 0;
}
Here's what the text file looks like:
207.14
177.34
150.55
104.22
86.36
53.97
52.55
58.77
64.66
120.32
153.45
170.90
And here's what the output looks like:
207.14
177.34
0
0
0
0
0
0
0
0
0
0
Your first entry in your file, "207.14" is actually "207.14 " -- (there's a space there). You read 7 characters but leave " " there, this means that istream::getline sets the failbit on inFile, meaning your successive getlines fail.
To fix this either read enough to reach the newline character, remove the space and/or clear inFiles failbit after your first getline.
You should also add a check within your for loop to handle any errors that may occur with fail/bad/eof bits.

Reading only SPECIFIC range of lines in a text file C++

Hi I have a text file which contains some numerical data. Of that text file ONLY the lines
14 to 100 have to be read into my C++ program. Each of these lines contain three numbers corresponding to x,y,z coordinates of a point. Thus, coordinates are given for 87 points in all.
I want to put these numbers into the arrays xp[87] yp[87] and zp[87].
How do I perform this?
Uptil now I have been used to the following
ifstream readin(argv[1])//Name of the text file
for (int i=0; i<=86; ++i)
{
readin>>xp[i]>>yp[i]>>zp[i];
}
But this technique works only for those files which contain 87 lines and the data to be read starts from the first line itself.
In the present case I want to ignore ALL lines before line 14 and ALL lines after line 100
Read line by line, for most flexibility in your format:
#include <fstream>
#include <sstream>
#include <string>
std::ifstream infile("thefile.txt");
std::string line;
unsigned int count = 0;
while (std::getline(infile, line))
{
++count;
if (count > 100) { break; } // done
if (count < 14) { continue; } // too early
std::istringstream iss(line);
if (!(iss >> x[count - 14] >> y[count - 14] >> z[count - 14]))
{
// error
}
}
// all done
In the present case I want to ignore ALL lines before line 14
Since you have to actually read the file to know where a line ends and a new one begins, you will have to then read 13 lines. Use getline() and a dummy string to hold the results from it.
and ALL lines after line 100
Just close the stream and be done with it.
After several years, Range-v3 allows one to write this:
#include <fstream>
#include <iostream>
#include <range/v3/view/drop.hpp>
#include <range/v3/view/getlines.hpp>
#include <range/v3/view/take.hpp>
using namespace ranges;
using namespace ranges::views;
int main() {
std::ifstream ifs{"inputFile"};
auto lines = getlines(ifs) | take(100) | drop(15/* which is 14 - 1 */);
for (auto i : lines) {
std::cout << i << std::endl;
}
}
Requires C++17.