Looping over file, only get one line - c++

Say we have a text file with this contents:
dogs
cats
bears
trees
fish
rocks
sharks
these are just words separated by newline chars. I am trying to create a Node.js addon. The Addon will read through a file and replacing matching lines with a blank line. Say I pass my program a regex that matches /trees/. If I pass the file to my C++ program it will read + write to the file, and result in:
dogs
cats
bears
fish
rocks
sharks
Right now, the problem is it's not looping through all the lines in the file. I get the feeling that's opening the file in append mode and therefore just starting at the end of the file? I can't tell. Anyway, I want to edit the file in place, not truncate and re-write or replace the whole file, because this will interrupt processes which are tailing the file.
Here's the code:
#include <nan.h>
#include <fstream>
#include <sstream>
#include <string>
#include <iostream>
using namespace std;
void Method(const Nan::FunctionCallbackInfo<v8::Value>& info) {
info.GetReturnValue().Set(Nan::New("world").ToLocalChecked());
}
void Init(v8::Local<v8::Object> exports) {
fstream infile("/home/oleg/dogs.txt");
if(infile.fail()){
cerr << " infile fail" << endl;
exit(1);
}
int pos = 0;
string line;
int count = 0;
while (getline(infile, line)){
// we only seem to loop once, even though the file has 7 or 8 items
count++;
long position = infile.tellp();
cout << "tellp position is " << position << endl;
string str(line);
int len = str.length();
cout << " => line contains => " << line << endl;
cout << " line length is " << len << endl;
std::string s(len, ' '); // create blank string of certain length
infile << s; // write the string to the current position
pos = pos + len;
cout << "pos is " << pos << endl;
}
cout << " => count => " << count << endl;
infile.close();
exports->Set(Nan::New("hello").ToLocalChecked(),
Nan::New<v8::FunctionTemplate>(Method)->GetFunction());
}
NODE_MODULE(hello, Init)
to compile the code you might need to use Node.js tooling, which is
node-gyp rebuild
If you want to help and want to try to compile the code, then let me know, because you may need more info. But I am a new C++ newb and I think someone can help me figure it out without compiling/running the code. Thanks.

To answer your question on why you only read one line of the input file:
Your first write to the file likely sets the eofbit on the stream, so the second getline() attempt will think it has no more to read.
The comment from #RSahu describes the simplest way to do this for text files.

Related

reading multiple lines of text until blank line

I'm working on a program that gets the user to enter text until the program reads a blank line. So far, I have this:
#include <iostream>
#include <cstring>
int main() {
string text;
cout << "Enter Your Text: " << endl;
getline(cin,text);
cout << "Text" << endl;
return 0;
}
But, this only outputs my text as a line and not individual lines, like I would like it to. And then there is the part when it reads a blank line that signifies the end of the user input.
I read that getline() gets all user input, but how do I display it as individual lines?
I read that I may have to use a tokenizer, but I am confused as to how they work, and how you actually write one. I was thinking of using a vector, or some kind of array, but vectors are the only ones I am sort of familiar with.
And I'm not quite sure how to get the program to stop at a blank line. I was thinking maybe a while loop, but what would go in the parenthesis, and how would that be combined with getting the user input?
What I'm basically trying to figure out is how to modify my code to output the user input as lines rather than one whole statement, and to stop getting user input when the user enters a blank line.
Try something like this:
#include <iostream>
#include <string>
#include <vector>
int main()
{
std::vector<std::string> text;
std::string line;
std::cout << "Enter Your Text: " << std::endl;
while (std::getline(std::cin, line) && !line.empty())
text.push_back(line);
std::cout << "You entered: " << std::endl;
for (auto &s : text)
std::cout << s << std::endl;
return 0;
}

Multiset: Problem with multiset adding more than one version of a word and cannot handle large amounts of text

Update and fixed: I have fixed the problem causing the error message- Huge thanks to user PaulMcKenzie for helping me understand what the error message was telling me!- When my program encountered a letter with a mark above it (diacritical marks I think they are called), it crashed. I have adjusted my code to account for these and now it doesn't crash at all! Another huge thanks to user ihavenoidea for helping me understand multisets! My program is now working the way it's supposed to!
Original post:
****I am VERY new to C++ so any and all help is appreciated!****
Ok, so I'm trying to use multiset to sort words so I can see how many times a word appears in a text. First, my program accepts a file, then it reads the words and takes out any punctuation, then it puts it into a multiset. After this, it is supposed to put the results into a text file the user names themselves.
My first issue is that the multiset seems to be creating more than one element for the same word (For example: in one of my tests I saw a(4) listed in the text document 3 times in a row instead of one time).
My Second issue is that when I try to read in large text documents (I'm using John Colliers story "Bottle Party" http://ciscohouston.com/docs/docs/greats/bottle_party.html to test it) my program completely crashes but doesn't crash when I test it with a smaller text document (small being with say about 5-10 lines of text). I'm using Visual Studios and (once again I'm new to Visual Studios also) I don't know what the error message is trying to tell me but it says:
After selecting retry:
As always, any and all help is greatly appreciated.
Code here:
#include <iostream>
#include <string> //for strings
#include <fstream> //for files
#include <set> //for use of multiset
using namespace std;
string cleanUpPunc(string);
//Global variables
multiset <string> words; //will change back to local variable later
int main() {
//Starting variables
string fileName1 = "", fileName2 = "", input = "", input2 = ""; //To hold the input file and the file we wish to print data to if desired
ifstream fileStream; //gets infor from file
//Program start
cout << "Welcome to Bags Program by Rachel Woods!" << endl;
cout << "Please enter the name of the file you wish to input data from: ";
getline(cin, fileName1);
//Trys to open file
try {
fileStream.open(fileName1);
if (!fileStream) {
cerr << "Unable to open file, please check file name and try again." << endl;
system("PAUSE");
exit(1);
}
while (fileStream >> input) {
input2 = cleanUpPunc(input); //sends the input word to check for punctation
words.insert(input2); //puts the 'cleaned up' word into the multiset for counting
}
fileStream.close();
//Sends it to a text document
cout << "Please name the file you would like to put the results into: ";
getline(cin, fileName2);
ofstream toFile; //writes info to a file
//Code to put info into text file
toFile.open(fileName2);
if (toFile.is_open()) {
multiset<string>::iterator pos;
for (pos = words.begin(); pos != words.end(); pos++) {
toFile << *pos << " " << words.count(*pos) << endl;
}
toFile.close();
cout << "Results written to file!" << endl;
}
else {
cout << "Could not create file, please try again." << endl;
}
}catch (exception e) {
cout << "Stop that. ";
cout << e.what();
}
cout << "Thanks for using this program!" << endl;
system("PAUSE");
return 0;
}
string cleanUpPunc(string maybe) {
//Takes out puncuation from string
//Variables
string takeOut = maybe;
//Method
for (int i = 0, len = maybe.size(); i < len; i++) {
if (ispunct(takeOut[i])) {
takeOut.erase(i--, 1);
len = takeOut.size();
}
}
return takeOut;
}

C++ opening a .txt file and creating a new one

So I'm trying to make a program that will open up a text file based on user input (or fail trying), read the contents and create a new text file named after user input and rewrite the contents, but this time with row numbers.
I'm having trouble that I can't pin down on anything specific. My Qt Creator gives no massive errors, but the program seems to halt around line 30 without any error messages.
An online C++ compiler complained about a segmentation problem.
The code:
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
using namespace std;
int main() {
string input_file = "";
cout << "input file: ";
getline(cin, input_file);
vector<string> line_vector;
string output_file = "";
cout << "output file:";
getline(cin, output_file);
ifstream file_object(input_file);
if ( not file_object )
{
cout <<"Error! The file " << input_file <<
" cannot be opened." << endl;
} else {
int row_number = 0;
string line;
while (getline(file_object, line) )
{
cout << line << endl;
line_vector[row_number] = line;
++row_number;
}
file_object.close();
ofstream output_file;
output_file.open("");
for (int i = 0; i>=row_number;++i)
{
output_file << i << " " << line_vector[i] << "\n";
}
output_file.close();
}
}
What the code is doing on this line: line_vector[row_number] = line is not actually appending to the vector - which is what you are trying to do -, but instead accessing an element at the index i inside the vector, and trying to assign line to it.
This would be fine, however, since the vector has 0 size, it is trying to assign line to unknown memory. This leads to undefined behaviour, and often, crashes. You can do one of two things. The first is to use resize or reserve to reserve the memory for the vector, then assign the variable, like so:
while (getline(file_object, line) ) {
cout << line << endl;
line_vector.resize(row_number + 1);
line_vector[row_number] = line;
++row_number;
}
However, this is pretty pointless, and instead, you should use push_back:
while (getline(file_object, line) ) {
cout << line << endl;
line_vector.push_back(line);
}
nullifying the use of row_number in that loop.
Oh, and don't use using namespace std, it's a bad habit.
"When you define a vector like line_vector, it starts out empty. All indexing into it will be out of bounds and lead to undefined behavior. Please learn how to push back elements into a vector. "
– Some programmer dude

How to show contents of the file in C++

I have some code here
https://github.com/Fallauthy/Projects/blob/master/cPlusPlusProjects/bazaPracownikow/bazaPracownikow/bazaPracownikow/main.cpp
And I have no idea how to show contents in my file. I mean i know how, but it doesn't show same I Have in file (in link). It show in next line. This code is responsible to load file
while (!baseFile.eof()) {
//wczytaj zawartosc pliku do zmiennej
std::string buffer;
baseFile >> buffer;
//wypisz
loadLineFromBase += buffer;
loadLineFromBase += " \n";
}
std::cout << loadLineFromBase << std::endl;
Unless I see all your code all I can do for you is give you a sample in return, I don't know what you're trying to do but it seems in this case you're looking for this.
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main()
{
string Display = "";
ofstream FileOut;
ifstream FileInput;
FileOut.open("C:\\Example.txt");
FileOut << "This is some example text that will be written to the file!";
FileOut.close();
FileInput.open("C:\\Example.txt");
if (!FileInput)
{
cout << "Error File not Found: " << endl;
return 1;
}
while (!FileInput.eof())
{
getline(FileInput, Display);
}
FileInput.close();
cout << Display << endl;
return 0;
}
Simply put if you're currently working wit ha text document
use getline()
When you use getline() it takes two arguments the first will be in this case your ifstream object, as in what you're using to open the file. The second will be the string you're using to store the contents in.
Using the method I outlined above you'll be able to read the entire file contents.
And please next time as it was said above outline your problem more in depth and if you provide us with all of your code we may better assist you!
Your snippet of code automatically add a newline to every string read from the input file, even if originally those were words separeted by spaces. Probably you want to keep the structure of the original file, so it's better to read one line at a time and, unless you need it for some other uses, print it out in the same loop.
std::string buffer;
// read every line of baseFile till EOF
while ( std::getline(baseFile, buffer) ) {
std::cout << buffer << '\n';
}

why does vector.size() read in one line too little?

when running the following code, the amount of lines will read on less then there actually is (if the input file is main itself, or otherwise)
why is this and how can i change that fact (besides for just adding 1)?
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main()
{
// open text file for input
string file_name;
cout << "please enter file name: ";
cin >> file_name;
// associate the input file stream with a text file
ifstream infile(file_name.c_str());
// error checking for a valid filename
if ( !infile ) {
cerr << "Unable to open file "
<< file_name << " -- quitting!\n";
return( -1 );
}
else cout << "\n";
// some data structures to perform the function
vector<string> lines_of_text;
string textline;
// read in text file, line by line
while (getline( infile, textline, '\n' )) {
// add the new element to the vector
lines_of_text.push_back( textline );
// print the 'back' vector element - see the STL documentation
cout << "line read: " << lines_of_text.back() << "\n";
}
cout<<lines_of_text.size();
return 0;
}
The code you have is sound. Here's a small test case that might help:
void read_lines(std::istream& input) {
using namespace std;
vector<string> lines;
for (string line; getline(input, line);) {
lines.push_back(line);
cout << "read: " << lines.back() << '\n';
}
cout << "size: " << lines.size() << '\n';
}
int main() {
{
std::istringstream ss ("abc\n\n");
read_lines(ss);
}
std::cout << "---\n";
{
std::istringstream ss ("abc\n123\n");
read_lines(ss);
}
std::cout << "---\n";
{
std::istringstream ss ("abc\n123"); // last line missing newline
read_lines(ss);
}
return 0;
}
Output:
read: abc
read:
size: 2
---
read: abc
read: 123
size: 2
---
read: abc
read: 123
size: 2
I think I have tracked down the source of your problem. In Code::Blocks, a completely empty file will report that there is 1 line in it (the current one) in the gizmo on the status bar at the bottom of the IDE. This means that were you actually to enter a line of text, it would be line 1. In other words, Code::Blocks will normally over-report the number of actual lines in a file. You should never depend on CB, or any other IDE, to find out info on files - that's not what they are for.
Well, if the last line of your file is just '\n', you don't push it into the vector. If you want it to be there, change the loop to:
while (getline( infile, textline, '\n' ).gcount() > 0)
{
if (infile.fail()) break; //An error occurred, break or do something else
// add the new element to the vector
lines_of_text.push_back( textline );
// print the 'back' vector element - see the STL documentation
cout << "line read: " << lines_of_text.back() << "\n";
}
Use the gcount() member to check how many characters were read in the last read - this will return 1 if it only read a delimiter character.
Ok so here is an explanation that you will hopefully understand. Your code should work fine if the file we're talking about doesn't end with newline. But what if it does? Let's say it looks like this:
"line 1"
"line 2"
""
Or as a sequence of characters:
line 1\nline 2\n
This file has THREE lines -- the last one being empty but it's there. After calling getline twice, you've read all the characters from the file. The third call to getline will say oops, end of file, sorry no more characters so you'll see only two lines of text.