Read part of txt file with C++ - c++

I have a question regarding reading a *.txt file with C++. I'm trying to read only the part of data between some specific sign like [start] and [end].
How I can do that?
I know how to open and read the whole file but I don't know how to read only a part of it with such requirements.

Use std::string and std::getline to filter out lines and go from there. Example:
std::ifstream input("someText.txt");
std::string line;
unsigned int counter = 0;
while (std::getline(input, line))
{
std::cout << "line " << counter << " reads: " << line << std::endl;
counter++;
}
Furthermore you can use the substr() method of the std::string class to filter out sub strings. You can also tokenize words (instead of lines) with std::getline using the optional third argument, which is the tokenizer. Example:
std::ifstream input("someText.txt");
std::string word;
unsigned int counter = 0;
while (std::getline(input, word, ' '))
{
std::cout << "word #" << counter << " is: " << word << std::endl;
counter++;
}

The way to go here would be to read word by word until you get the wanted start tag, then you read and save all words until the end tag is read.

If you are creating that .txt file by yourself, create it in a structured way, keeping offsets and size of different blocks in the beginning. if so, you can read the offset of required block of data from the beginning and jump to there using fseek (or similar). Otherwise, you have to read word by word.

Related

C++ Read from stdin if within size

I want to read from stdin if that is within a size. How do I restrict that in this code?
std::cout << "Enter a string till end of line: " << std::endl;
std::isstreambuf_iterator<char> begin(std::cin), end;
std::string str(begin, end);
What I want is to restrict the read from stdin to maximum length of 10. If it is, then I would assign it to string str. Please help!
Read a line. Make sure it's not too big. Use the line.
Example:
std::cout << "Enter a string till end of line: " << std::endl;
std::string line;
if std::getline(std::cin, line)) // read in until end of line or end of stream
{
if (line.size <= maximum_size) // ensure line isn't too big
{
// process line here
}
}
else // read failed
{
// May need some clean-up to handle failed input stream
}
I'd suggest you to read char-by-char from cin. Use functions:
cin.get(...)
or
char c;
cin >> c;
By this way you would control length and end-of-line.

Looping over file, only get one line

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.

C++ file input with mixed delimiters and data types

I am trying to input data from a text file:
The line format is as follows...
String|String|int double
Example:
Bob|oranges|10 .89
I can get the line in as a string using
Getline(infile, line)
I don't understand how to break the line into the distinct variables from the string variable.
Thanks
for a start you could write some good old fashioned c code using strchr.
Or use string.find / find_first_of if you are using std::String
http://www.cplusplus.com/reference/string/string/find_first_of/
You marked this as C++. So perhaps you should try to use formatted extractors ...
Here is a 'ram' file (works just like a disk file)
std::stringstream ss("Bob|oranges|10 .89");
// this ^^^^^^^^^^^^^^^^^^ puts one line in file
I would use getline for the two strings, with bar terminator
do {
std::string cust;
(void)std::getline(ss, cust, '|'); // read to 1st bar
std::string fruit;
(void)std::getline(ss, fruit, '|'); // read to 2nd bar
Then read the int and float directly:
int count = 0;
float cost;
ss >> count >> cost; // the space char is ignored by formatted extraction
std::cout << "\ncust: " << cust << "\n"
<< " " << count << " " << fruit
<< " at $" << cost
<< " Totals: " << (float(count) * cost) << std::endl;
if(ss.eof()) break;
}while(0);
If you are to handle more lines, you need to find the eoln, and repeat for every record of the above style.
This approach is extremely fragile (any change in format will force a change in your code).
This is just to get your started. It has been my experience that using std::string find and rfind is much less fragile.
Good luck.

File Line count using boost

If I have a boost::filesystem::path object, how can I get the line count of this file?
I need to compare the line counts of two files as a precondition check.
You can do something like this:
std::ifstream file(path.c_str());
// Number of lines in the file
int n = std::count(std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>(), '\n');
Where path is a boost::filesystem::path. This will count the number of \n in the file so you need to pay attention if there is a \n at the end of the file to get the right number of lines.
You can use ifstream and getline to read file by line, and count it.
std::ifstream filein("aaa.txt");
int count = 0;
std::string line;
while (std::getline(filein, line))
{
count++;
}
std::cout << "file line count is " << count;
With stringstream, I advise to use intermediate string otherwise the streamstring will be consumed during the count and the iterator will not be at the beginning of the string for next getline.
string s = string("1\n2\n3\nlast");
stringstream sstream(s);
int nbOfLines = std::count(s.begin(), s.end(), '\n');
cout << "Nb of lines is: " << nbOfLines << endl;
Result:
Nb of lines is: 3
You can do getline from the beginning.
Or, for better performances (less copy), seek back to the beginning
int nbOfLines = std::count(std::istreambuf_iterator<char>sstream),std::istreambuf_iterator<char>(), '\n');
sstream.seekg(0, ios_base::beg);

How to check if stringstream>>string will put nothing on the string?

For example, when parsing a text file, some times this file have stuff like this:
keyword a string here
keyword another string
keyword
keyword again a string
Note that the 3th line have an empty string (nothing or white spaces).. The thing is that when you do stringstream>>laststring, and stringstream have an empty string (null or just white space), it will not overwrite the "laststring", it will do nothing. Theres anyway to check this situation before hand? I dont want to create a temp empty string just to check it is still empty after stringstream>>, seems lame.
When you cannot read from stream - its state changes, so when casting to bool, it returns false:
bool read = static_cast<bool>(ss >> laststring);
Or - in if-expr:
if (ss >> laststring)
cout << "Just read: " << laststring;
See example
You can only know after trying to read whether there was something or not. What you might be able to do is to skip whitespace and see if there is a non-space in the next location:
if ((in >> std::ws).peek() != std::char_traits<char>::eof()) {
...
}
Given that empty strings are cheap to create, I wouldn't bother and try read the string. Note, however, that reading from streams isn't line based, i.e., in your case above you need to split the lines first or use something like std::getline() to read the second part of line.
You can use getline, to read a line from the file. Then, copy the line into a string stream and read words from the string stream one at a time. The streams will automatically stop reading when they run out of lines / words.
// open file
std::ifstream fin("text.txt");
// 'iterate' through all the lines in the file
unsigned lineCount = 1;
std::string line;
while (std::getline(fin, line))
{
// print the line number for debugging
std::cout << "Line " << lineCount << '\n';
// copy line into another stream
std::stringstream lineStream(line);
// 'iterate' through all the words in the line
unsigned wordCount = 1;
std::string word;
while (lineStream >> word)
{
// print the words for debugging
std::cout << '\t' << wordCount++ << ' ' << word << '\n';
}
}
You need to include iostream, fstream, sstream and string.
For checking if string is empty, use foo.size() == 0.
For checking if string stream is empty fooStream.rdbuf()->in_avail() == 0