Read from a file with blank spaces in C++ - c++

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.

Related

Read a file .txt C++

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.

C++ how to remove all chars and special characters from a file

I have seen how to remove specific chars from a string but I am not sure how to do it with a file open or if you can even do that. Basically a file will be open with anything in it, my goal is to remove all the letters a-z, special characters, and whitespace that may appear so that all that is left is my numbers. Can you easily remove all chars rather than specifying a,b,c etc when the file is open or would I have to convert it to a string? Also would it be better to do this in memory?
My code this far as is follows:
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main() {
string filename;
cout << "Enter the name of the data file to open" << endl;
cin >> filename >> endl;
ofstream myfile;
myfile.open(filename);
if (myfile.is_open()) { //if file is open then
while(!myfile.eof()){ //while not end of file
//remove all chars, special and whitespace
}
}
else{
cout << "Error in opening file" << endl;
}
return 0;
}
Preliminary remarks
If I understand well, you want to keep only the numbers. Maybe it's easier to retain chars that are ascii numbers and eliminate the others rather than eliminate a lot of other chars classes and hope that the remainder is only numbers.
Also never loop on eof to read a file. Loop on the stream instead.
finally, you should read from an ifstream and write to an ofstream
First approach: reading strings
You can read/write the file line by line. You need enough memory to store the largest line, but you benefit from buffering effect.
if (myfile.is_open()) { //if file is open then
string line;
while(getline(myfile, line)){ //while succesful read
line.erase(remove_if(line.begin(), line.end(), [](const char& c) { return !isdigit(c); } ), line.end());
... // then write the line in the output file
}
}
else ...
Online demo
Second approach: reading chars
You can read/write char by char, which gives very flexible option for handling individual characters (toggle string flags, etc...). You also benefit from buffering, but you have function call overhaead for every single char.
if (myfile) { //if file is open then
int c;
while((c = myfile.get())!=EOF){ //while succesful read
//remove all chars, special and whitespace
if (isdigit(c) || c=='\n')
... .put(c); // then write the line in the output file
}
}
else ...
Online demo
Other approaches
You could also read a large fixed size buffer, and operate similarly as with the strings (but don't eliminate LF then). The advantage is that the memory need is not impacted by some very large lines in the file.
You could also determine the file size, and try to read the full file at once (or in very large chunks). You'd then maximize performance at the cost of memory consumption.
This is just an example in order to extract all chars you want from a file with a dedicated filter:
std::string get_purged_file(const std::string& filename) {
std::string strbuffer;
std::ifstream infile;
infile.open(filename, std::ios_base::in);
if (infile.fail()) {
// throw an error
}
char c;
while ((infile >> c).eof() == false) {
if (std::isdigit(c) || c == '.') {
strbuffer.push_back(c);
}
}
infile.close();
return strbuffer;
}
Note: this is just an example and it has to be subject to optimizations. Just to give you an idea:
Read more than one char at time, (with a proper buffer).
Reserve memory in string.
Once you have the buffer "purged" you can overwrite your file on save the content into another file.

Error using getline with ifstream - C++

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].

Using C++ ifstream extraction operator>> to read formatted data from a file

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.

Why is this IO operation looping infinitely?

I am trying to read from a text file and tokenize the input. I was getting a segmentation fault until I realized I forgot to close my ifstream. I added the close call and now it loops infinitely. I'm just trying to learn how to use strtok for now, that is why the code doesn't really look complete.
void loadInstructions(char* fileName)
{
ifstream input;
input.open(fileName);
while(!input.eof());
{
string line;
getline (input,line);
char * lineChar = &line[0];
//instruction cmd; //This will be used later to store instructions from the parse
char * token;
token = strtok (lineChar," ");
// just trying to get the line number for now
int lineNumber = atoi(token);
cout << lineNumber << "\n";
}
input.close();
}
input file:(one line)
5 +8 0 0 25
This while(input.good()); is probably not what you intended...
Use this:
string line;
while(getline (input,line))
{
If the getline() works then the loop is entered.
If you try and read past the EOF then it will fail and the loop will exit.
So this should word as expected.
Rather than using strtok() (which damages the string) and atoi() which is non portable.
Use std::stringstream
std::stringstream linestream(line);
int lineNumber;
linestream >> lineNumber; // reads a number from the line.
Don't explicitly close() the stream (unless you want to detect and correct for any problems). The file will be closed when the object goes out of scope at the end of the function.
You want to use eof() not good().
Avoid strtok. There are other ways to tokenize a string that do not require the called function to modify your string. The fact that it modifies the string it tokenizes could also be what causes the loop here.
But more likely, the good() member is not the right one. Try !input.eof() or similar, depending on what you need.
While you've already gotten some answers to the question you asked, perhaps it's worth answering some you should have about the code that you didn't ask:
void loadInstructions(char* fileName)
Since the function isn't going to modify the file name, you almost certainly want to change this to:
void loadInstructions(char const *fileName)
or
void loadInstructions(std::string const &fileName)
ifstream input;
input.open(fileName);
It's much cleaner to combine these:
ifstream input(fileName);
or (if you passed a string instead):
ifstream input(fileName.c_str());
while(!input.eof());
This has already been covered.
string line;
getline (input,line);
char * lineChar = &line[0];
//instruction cmd; //This will be used later to store instructions from the parse
char * token;
token = strtok (lineChar," ");
// just trying to get the line number for now
int lineNumber = atoi(token);
Most of this is just extraneous. You can just let atoi convert directly from the original input:
string line;
getline(input, line);
int lineNumber = atoi(line);
If you're going to tokenize more later, you can use strtol instead:
char *end_ptr;
int lineNumber = strtol(line, &end_ptr, 10);
This will set end_ptr to point just past the end of the part that strtol converted.
I'd also consider an alternative though: moving your code for reading and parsing a line into a class, and define operator>> to read those:
struct line {
int number;
operator int() { return number; }
};
std::istream &operator>>(std::istream &is, line &l) {
// Just for fun, we'll read the data in an alternative fashion.
// Instead of read a line into a buffer, then parse out the first number,
// we'll read a number from the stream, then ignore the rest of the line.
// I usually prefer the other way, but this is worth knowing as well.
is >> l.number;
// When you're ready to parse more, add the extra parsing code here.
is.ignore(std::numeric_limits<std::istream::pos_type>::max, '\n');
return is;
}
With this in place, we can print out the line numbers pretty easily:
std::copy(std::istream_iterator<line>(input),
std::istream_iterator<line>(),
std::ostream_iterator<int>(std::cout, "\n"));
input.close();
I'd usually just let the stream close automatically when it goes out of scope.