I have read a CSV file that has line ending character as '\r', the reading operation done successfully, but the problem started when i pass the read line in to the while(getline(ss,arr2,',')) for separating comma..it does work properly for the first line but all the next iterations are empty(i.e)it has been failing to separate the comma in the string.
int main()
{
cout<<"Enter the file path :";
string filename;
cin>>filename;
ifstream file;
vector<string>arr;
string line,var;
stringstream content;
file.open(filename.c_str(),ios::in );
line.assign((std::istreambuf_iterator<char>(file)),
std::istreambuf_iterator<char>());
file.close();
string arr2;
stringstream ss;
content<<line;
//sqlite3 *db;int rc;sqlite3_stmt * stmt;
int i=0;
while (getline(content,var,'\r'))
{
ss.str(var);//for each read the ss contains single line which i could print it out.
cout<<ss.str()<<endl;
while(getline(ss,arr2,','))//here the first line is neatly separated and pushed into vector but it fail to separate second and further lines i was really puzzled about this behaviour.
{
arr.push_back(arr2);
}
ss.str("");
var="";
arr2="";
for(int i=0;i<arr.size();i++)
{
cout<<arr[i]<<endl;
}
arr.clear();
}
getch();
}
what went wrong in the above...I see nothing right now:(
The stringstream::str method does not reset / clear the internal state of the stream. After the first line, the internal state of ss is EOF (ss.eof() returns true).
Either use a local variable inside the while loop:
while (getline(content,var,'\r'))
{
stringstream ss(var);
Or clear the stream before ss.str:
ss.clear();
ss.str(var);
Related
How should I read lines with spaces from a file.txt and record it in my vector?
I have a line that consists of many words ,but my loop doesn't see that and read them one by one and print in that way:
For example,I have a string in a file:
Hello, my friends,how are you?
Hello,James, we are fine.
And in my console, I see:
Hello,
my
friends
....
fine
This my loop:
while(rRecord»str)
{
lines.push_back(str);
}
And my function that prints my words:
void printRecord(int& numStr,struct winsize w,std::vector<std::string>& lines)
{
for (int i = numStr; i < numStr + w.winsize::ws_row-1; i++)
{
if (i>=lines.size())
break;
else
std::cout « lines[i] « std::endl;
}
numStr += w.winsize::ws_row;
}
To read line-by-line, use std::getline, like this:
std::string line;
while (std::getline(inFile, line)) {
lineVector.push_back(std::move(line));
}
The std::move means that when the vector creates the new element, it can "steal" the internal buffer from line, meaning line will now be an empty string, but saves an extra allocation+copy.
Be aware that mixing getline with >> is usually not a good idea, because >> will leave any trailing whitespace, including a newline, in the stream, meaning you get unexpected results the next time you try to getline.
I need help, I tried googling if I could find a similar problem but the solutions for others didn't work for me.
I'm trying to use getline() to read the file I've opened but it's not accepting the parameters I've given it.
What I'm trying to accomplish at this time (not the entire program) is to open a .csv file and determine how many elements it has inside by using getline() and using the , character as the delimiter. My loop has an index which I could just add 1 to it so that I can get the total number of elements inside the file.
The reason I'm doing this is because I intend to use it for a project at school but so far I've gotten stuck at the getline() error:
no matching function for call to 'std::basic_ifstream::getline(std::string&, int, const char [2])'
My code is here:
void readfile(string a)
{
int i = 0;
ifstream infile;
infile.open(a.c_str());
string temp;
//count how many elements are inside
if(infile.is_open())
{
while(infile.good())
{
infile.getline(temp, 256, ",");
i++;
}
infile.close();
i+=1;
}
else
{
cout<<"Error opening file.";
}
cout<<i;
}
Use the free getline() function:
std::string line;
getline(infile, line);
In addition to the answer by #UlrichEckhardt, I'd handle delimiters like this:
if(infile.is_open())
{
string temp;
// std::getline(std;:istream&, std::string) used below
while(getline(infile, temp)) {
std::stringstream stream(str);
std::string token;
while (std::getline(stream, token, ','))
if (!token.empty()) // it's up to you to decide how to handle empty tokens
i++;
}
}
Note the ','. If it were ".", this would be considered a string by the compiler, which is exactly what you're seeing in the error message: a '\0' is appended automatically, thus producing a char[2].
stringstream always seems to fail when I call stringstream::ignore(), even if this is done after calling stringstream::clear():
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <cassert>
using namespace std;
int main() {
int a, b;
stringstream ss;
string str;
ifstream inFile("file.txt");
if(!inFile) {
cerr << "Fatal: Cannot open input file." << endl;
exit(1);
}
while(getline(inFile, str)) {
ss << str; // read string into ss
ss >> a >> b; // stream fails trying to store string into int
ss.clear(); // reset stream state
assert(ss.good()); // assertion succeeds
ss.ignore(INT_MAX, '\n'); // ignore content to next newline
assert(ss.good()); // assertion fails, why?
}
return 0;
}
file.txt contains the following text:
123 abc
456 def
Why is ss.good() false after ss.ignore()?
std::endl outputs \n and flushes the stream. However, stringstream::flush() is meaningless and does nothing. flush only has meaning when the underlying buffer is tied to an output device like the terminal, however, a stringstream has nowhere to flush the contents to. If you want to clear the contents of a stringstream do ss.str(""); instead. However, I would probably change the code to the following:
while(getline(inFile, str)) {
ss.str(str); // call ss.str() to assign a new string to the stringstream
if(!ss >> a >> b) // check if stream fails trying to store string into int
{
ss.clear(); // Read failed, so reset stream state
}
else
{
// Read successful
}
// Do other stuff
}
Also, if you want to insert a newline into the stringstream, just do ss << '\n'; and do not call std::endl.
It turns out there is no newline at the end of ss. After executing the following statements:
getline(infile, str);
ss << str;
ss will not contain a newline character, because getline() does not add a newline character to the end of the string stored into the second parameter. As a result, when this statement is executed:
ss.ignore(INT_MAX, '\n');
the stream fails because it reaches the end of the stream without finding a newline character to stop at.
ss.ignore() is not necessary if ss.str() is used to store the string, which replaces the entire contents of the stream. Should the stream fail, it should be reset and its contents set to the empty string "". Alternatively, ss.ignore() could be used, but only as long as a newline character is inserted into the stream immediately after the data is read so that it does not cause the stream to fail—but this would be redundant if the contents of the stream is later set to another value using ss.str().
A successful read of the next line of the file can be ensured by calling ss.clear() before the stream is assigned the contents of the next line of the file, since the old contents of the stream are overwritten on ss.str(). The stream state can be reset at the beginning of the loop, and no problems would occur even if the stream fails later in the loop:
while(getline(inFile, str)) {
ss.clear(); // make sure stream is good
ss.str(str); // overwrite contents of stream with str
ss >> a >> b;
// Even if the stream fails after this line, the stream is reset before each
// line is stored into the stream, and no problems should occur while reading
// and parsing subsequent lines in the file.
// Code to validate and store data from file...
}
I am reading from a file and passing the front of the array(pointer) back into my main function. The problem I am having is that it is not copying the blank spaces in between the words. For example Hello Hello comes out as HelloHello.
I started by using getLine instead and ran into the problems of size of the file. I set it to 500 because no files will be larger than 500, however most files will be below 500 and I am trying to get the exact size of the file.
Here is my code:
char infile()
{
const int SIZE=500;
char input[SIZE];
char fromFile;
int i=0;
ifstream readFile;
readFile .open("text.txt");
while(readFile>>fromFile)
{
input[i]=fromFile;
i++;
}
cout<<endl;
returnArray=new char[i];//memory leak need to solve later
for(int j=0;j<i;j++)
{
returnArray[j]=input[j];
cout<<returnArray[j];
}
cout<<endl;
}
return returnArray[0];
}
Depending on what your file format is, you may want to use ifstream::read() or ifstream::getline() instead.
operator >> will attempt to 'tokenize' or 'parse' the data stream as it is being read, using whitespace as separators between tokens. You're interested in getting the raw data from the file with whitespace intact, therefore you should avoid using it. If you want to read data in one line at a time, using linefeeds as separators, you should use getline(). Otherwise use read().
Use std::string, std::vector and std::getline and you can still return a char. That will solve your memory leak and skipping whitespace problem.
Example:
char infile()
{
std::ifstream readFile("text.txt");
std::vector<std::string> v;
std::string line;
while(std::getline(readFile, line))
{
v.push_back(line);
}
for(auto& s : v)
{
std::cout << s << std::endl;
}
return (v[0])[0];
}
You are asking it to read while delimiting where there is whitespace.
You can use getline() to preserve the whitespace.
As my learning, I am trying to use c++ ifstream and its operator>> to read data from a text file using code below. The text file outdummy.txt has following contents:
just dummy
Hello ofstream
555
My questions is how to read char data present in the file into a char array or string. How to do this using the ifstream::operator>> in code below.
#include <iostream>
#include <fstream>
int main()
{
int a;
string s;
char buf[100];
ifstream in("outdummy.txt",ios_base::in);
in.operator>>(a); //How to read integer? How to read the string data.??
cout << a;
in.close();
getchar();
return 0;
}
If you want to use formatted input, you have to know in advance what data to expect and read it into variables of the according data type. For example, if you know that the number is always the fifth token, as in your example, you could do this:
std::string s1, s2, s3, s4;
int n;
std::ifstream in("outdummy.txt");
if (in >> s1 >> s2 >> s3 >> s4 >> n)
{
std::cout << "We read the number " << n << std::endl;
}
On the other hand, if you know that the number is always on the third line, by itself:
std::string line;
std::getline(in, line); // have line 1
std::getline(in, line); // have line 2
std::getline(in, line); // have line 3
std::istringstream iss(line);
if (iss >> n)
{
std::cout << "We read the number " << n << std::endl;
}
As you can see, to read a token as a string, you just stream it into a std::string. It's important to remember that the formatted input operator works token by token, and tokens are separated by whitespace (spaces, tabs, newlines). The usual fundamental choice to make is whether you process a file entirely in tokens (first version), or line by line (second version). For line-by-line processing, you use getline first to read one line into a string, and then use a string stream to tokenize the string.
A word about validation: You cannot know whether a formatted extraction will actually succeed, because that depends on the input data. Therefore, you should always check whether an input operation succeeded, and abort parsing if it doesn't, because in case of a failure your variables won't contain the correct data, but you have no way of knowing that later. So always say it like this:
if (in >> v) { /* ... */ } // v is some suitable variable
else { /* could not read into v */ }
if (std::getline(in, line)) { /* process line */ }
else { /* error, no line! */ }
The latter construction is usually used in a while loop, to read an entire file line by line:
while (std::getline(in, line)) { /* process line */ }
ifstream has ios_base::in by default. You don't need to specify it.
operator>> can be invoked directly as an operator: in >> a.
Reading strings is the same: in >> s, but the caveat is that it is whitespace-delimited, so it will read "just" by itself, without "dummy".
If you want to read complete lines, use std::getline(in, s).
Since you have elected to use C-strings, you can use the getline method of your ifstream object (not std::getline() which works with std::strings), which will allow you to specify the C-string and a maximum size for the buffer.
Based on what you had, and adding an additional buffer for the second line:
char buf[100];
char buf2[100];
in.getline(buf,sizeof(buf));
in.getline(buf2,sizeof(buf2));
in >> a;
However, as the other poster has proposed, try using the std::string and its methods, it will make your life easier.
You can read file contents and use a Finite State Machine for parsing.
Example:
void Parse(const char* buffer, size_t length);
size_t GetBufferSize();
size_t bufferSize = GetBufferSize();
char* buffer = new char[bufferSize];
std::ifstream in("input.txt");
while(in.getline(buffer, bufferSize)) {
Parse(buffer, in.gcount());
}
Alternatively, you can use a tool like Flex to write your parser.