How to read-write into/from text file with comma separated values - c++

How do I read data from a file if my file is like this with comma separated values
1, 2, 3, 4, 5\n
6, 7, 8, 9, 10\n
\n
and after reading the file, I want to write the data back into other file as same format above.
I can get total number of lines, using
string line;
while(!file.eof()){
getline(file,line);
numlines++;
}
numline--; // remove the last empty line
but how can I know total number of digits in a row/line ??
I also have vector of ints to store the data.
So, I want to read the first line and then count total number of elements in that line, here 5 (1,2,3,4,5) and store them in array/vector, and read next line and store them in vector again and so on till I reach EOF.
Then, I want to write the data to file, again, I guess this will do the job of writing data to file,
numOfCols=1;
for(int i = 0; i < vector.size(); i++)
{
file << vector.at(i);
if((numOfCols<5) file << ",";//print comma (,)
if((i+1)%5==0)
{
file << endl;//print newline after 5th value
numOfCols=1;//start from column 1 again, for the next line
}
numOfCols++;
}
file << endl;// last new line
So, my main problem is how to read the data from file with comma separated values ??
Thanks

Step 1:
Don't do this:
while(!file.eof())
{
getline(file,line);
numlines++;
}
numline--;
The EOF is not true until you try and read past it.
The standard pattern is:
while(getline(file,line))
{
++numline;
}
Also note that std::getline() can optionally take a third parameter. This is the character to break on. By default this is the line terminator but you can specify a comma.
while(getline(file,line))
{
std::stringstream linestream(line);
std::string value;
while(getline(linestream,value,','))
{
std::cout << "Value(" << value << ")\n";
}
std::cout << "Line Finished" << std::endl;
}
If you store all the values in a single vector then print them out using a fixed width. Then I would do something like this.
struct LineWriter
{
LineWriter(std::ostream& str,int size)
:m_str(str)
,m_size(size)
,m_current(0)
{}
// The std::copy() does assignement to an iterator.
// This looks like this (*result) = <value>;
// So overide the operator * and the operator = to
LineWriter& operator*() {return *this;}
void operator=(int val)
{
++m_current;
m_str << val << (((m_current % m_size) == 0)?"\n":",");
}
// std::copy() increments the iterator. But this is not usfull here
// so just implement too empty methods to handle the increment.
void operator++() {}
void operator++(int) {}
// Local data.
std::ostream& m_str;
int const m_size;
int m_current;
};
void printCommaSepFixedSizeLinesFromVector(std::vector const& data,int linesize)
{
std::copy(data.begin(),data.end(),LineWriter(std::cout,linesize));
}

here I m posting the code for CSV read as well as write code. I have checked its working fine.
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
using namespace std;
void readCSV(istream &input, vector< vector<string> > &output)
{
string csvLine;
// read every line from the stream
while( getline(input, csvLine) )
{
istringstream csvStream(csvLine);
vector<string> csvColumn;
string csvElement;
// read every element from the line that is seperated by commas
// and put it into the vector or strings
while( getline(csvStream, csvElement, ',') )
{
csvColumn.push_back(csvElement);
}
output.push_back(csvColumn);
}
}
int main()
{
ofstream myfile;
string a;
fstream file("b.csv", ios::in);
myfile.open ("ab.csv");
if(!file.is_open())
{
cout << "File not found!\n";
return 1;
}
// typedef to save typing for the following object
typedef vector< vector<string> > csvVector;
csvVector csvData;
readCSV(file, csvData);
// print out read data to prove reading worked
for(csvVector::iterator i = csvData.begin(); i != csvData.end(); ++i)
{
for(vector<string>::iterator j = i->begin(); j != i->end(); ++j)
{
a=*j;
cout << a << " ";
myfile <<a<<",";
}
myfile <<"\n";
cout << "\n";
}
myfile.close();
system("pause");
}

Try the stringstream class:
#include <sstream>
Just in case, look up Stroustrup's "The C++ Programming Language Special Edition" page 641 example.
It works for me and I had a hell of a time trying to figure this one out.

Related

Read file and input into vector

Given a text file with the following fixed contents (only two lines, nothing more):
43 65 123 13 41
83 67 22
I need it to turn into a vector array where I can apply the name.size() to find out the length of the array and also to make use of the integers inside for other purposes.
The result should be:
Array 1: 43 65 123 13 41
Array 2: 83 67 22
Array 1 Length: 5
Array 2 Length: 3
I have successfully read the text file and added the content using .push_back(). However when I cout the vector .size(), it returns 2 and I realised that it consider each line as an element in the array.
What is the approach to tackling this?
Edit:
Added snippet of the code:
vector <string> readFile(const string& fileName)
{
ifstream source;
source.open(filename);
vector <string> lines;
string line;
while(getline(source, line)
{
lines.push_back(line);
} return lines;
}
int main(int argc, char ** argv)
{
string inputFile(argv[1]);
vector <string> fileData = readFile(inputFile);
// Check vector
for(auto i : fileData)
cout << i << endl;
// Check vector length
cout << fileData.size() << endl;
}
As already mentioned, std::getline and std::istringstream are good starting points.
Then you can use std::istream_iterator to create the vectors directly using the iterator overload of the std::vector constructor.
Perhaps something like this:
std::vector<std::vector<int>> read_file(std::istream& input)
{
std::vector<std::vector<int>> lines;
std::string line;
while (std::getline(input, line))
{
std::istringstream line_stream(line);
lines.emplace_back(std::istream_iterator<int>(line_stream),
std::istream_iterator<int>());
}
return lines;
}
This handles an arbitrary number of lines containing an arbitrary number of integer values.
Can be used something like this:
int main(int, char* argv[])
{
std::ifstream input(argv[1]);
auto data = read_file(input);
std::cout << "First line of data: ";
for (auto value : data[0])
{
std::cout << value << ' ';
}
std::cout << '\n';
std::cout << "Second line of data: ";
for (auto value : data[1])
{
std::cout << value << ' ';
}
std::cout << '\n';
}
Important note: The example above lacks any kind of error or range checking. It's left as an exercise for the reader.
You could read each one as a text line, then extract the numbers from the text.
std::vector<std::vector<int>> database;
std::string text_line;
while (std::getline(cin, text_line))
{
std::vector<int> numbers_row;
std::istringstream number_stream(text_line);
int value;
while (number_stream >> value)
{
numbers_row.push_back(value);
}
database.push_back(numbers_row);
}
The inner loop creates a vector based on the numbers in that text line.
The outer loop creates vectors and appends them to the database.
The common way is to use std::getline to read line by line, to put it in a std::istringstream and then to use formatted input from that stream - but you've already gotten answers for that so I'll throw in an alternative.
This uses formatted input directly from the ifstream (or any istream descendant) and peek()s to see if a newline (\n) is the next character.
It could look like this:
#include <istream>
#include <vector>
std::vector<std::vector<int>> read_stream(std::istream& is) {
std::vector<std::vector<int>> res;
std::vector<int> cur;
int x;
while(true) {
if(is.peek() == '\n') {
// save what we've gotten on the current line
res.emplace_back(std::move(cur));
cur.clear();
}
if(is >> x) cur.push_back(x);
else break;
}
return res;
}

unique words from a file c++

ts been 3 days i just cant identify whats wrong with the program the program should compare words by words instead it only comparing a character to charcter its is showing like if i have words like (aaa bbb cc dd ) the result its printing is a b and same is the sentence file if i put paragraphs to compare its only comparing few character please help me
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main()
{
ifstream myfile("unique.text");
int count = 0;
string temp;
string a;
int i,j;
while(getline(myfile,temp))
{
for(i=0 ; i < sizeof(temp); i++)
{
for(int j = 0; j < i; j++)
{
if (temp[i] == temp[j])
break;
}
if (i == j)
cout << temp [i] <<" , ";
}
myfile.close ();
}
You have a couple of problems
temp is of type string. sizeof is not the way to determine the length of a string (it's used for determining things like the number of bytes in an int). You want:
temp.length()
Secondly, indexing into a string (temp[n]) gives you the nth character, not the nth word.
You can make getline split into words by adding a third delimiter parameter:
getline (myfile, temp, ' '))
So, some bugs in your code.
Mixing up characters and strings, closing the file in the while loop and not storing last words.
One recommenadtion. Before you write code, write comments for what you want to do.
Meaning, make a design, before you start coding. That is very important.
For your problem at hand in the title of this thread:
unique words from a file c++
I prepared 3 different solutions. The first is just using very simple constructs. The second is using a std::vector. And, the 3rd is the C++ solution using the C++ algorithm library.
Please see:
Simple, but lengthy
And not recommended, because we should not use raw pointers for owned memory and should not use new
#include <iostream>
#include <fstream>
#include <string>
const std::string fileName{ "unique.text" };
unsigned int numberOfWords() {
// Here we will count the number of words in the file
unsigned int counter = 0;
// Open the file. File must not be already open
std::ifstream sourceFileStream(fileName);
// Check, if we could open the file
if (sourceFileStream) {
// Simply read all words and increment the counter
std::string temp;
while (sourceFileStream >> temp) ++counter;
}
else {
// In case of problem
std::cerr << "\nCould not open file '" << fileName << "'\n";
}
return counter;
}
int main() {
// Get the number of words in the source file
unsigned size = numberOfWords();
// Allocate a dynamic array of strings. Size is the count of the words in the file
// Including doubles. So we will waste a little bit of space
std::string* words = new std::string[size+1];
// Open the source file
std::ifstream sourceFileStream(fileName);
// Check, if it could be opened
if (sourceFileStream) {
// We will read first into a temporary variable
std::string temp;
// Her we will count number of the unique words
unsigned int wordCounter = 0;
// Read all words in the file
while (sourceFileStream >> temp) {
// We will search, if we have read alread the word before. We assume NO for the beginning
bool wordIsAlreadyPresent = false;
// Go through all alread read words, and check, if the just read word is already existing
for (unsigned int i = 0; i < wordCounter; ++i) {
// Check, if just read word is already in the word array
if (temp == words[i]) {
// Yes it is, set flag, and stop the loop.
wordIsAlreadyPresent = true;
break;
}
}
// if the word was not already there
if (! wordIsAlreadyPresent) {
// Then add the just read temporary word into our array
words[wordCounter] = temp;
// And increment the counter
++wordCounter;
}
}
// Show all read unique words
for (unsigned int i = 0; i < wordCounter; ++i) {
std::cout << words[i] << "\n";
}
}
else { // In case of error
std::cerr << "\nCould not open file '" << fileName << "'\n";
}
delete[] words;
}
Using a vector. Already more compact and better readable
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
const std::string fileName{ "unique.text" };
int main() {
// Open the source file
std::ifstream sourceFileStream(fileName);
// Check, if the source file is oepen
if (sourceFileStream) {
// Temporary string for holding just read words
std::string temp;
// In this vector we will store all unique words
std::vector<std::string> words;
// Read all words from the source file
while (sourceFileStream >> temp) {
// We will search, if we have read alread the word before. We assume NO for the beginning
bool wordIsAlreadyPresent = false;
// Go through all alread read words, and check, if the just read word is already existing
for (unsigned int i = 0; i < words.size(); ++i) {
// Check, if just read word is already in the word vector
if (temp == words[i]) {
// Yes it is, set flag, and stop the loop.
wordIsAlreadyPresent = true;
break;
}
}
// if the word was not already there
if (not wordIsAlreadyPresent) {
// Then add the just read temporary word into our array
words.push_back(temp);
}
}
for (unsigned int i = 0; i < words.size(); ++i) {
std::cout << words[i] << "\n";
}
}
else {
std::cerr << "\nCould not open file '" << fileName << "'\n";
}
}
And 3., more advance C++ programming. Just very few lines and elegant code.
But too difficult to understand for starters.
#include <iostream>
#include <fstream>
#include <set>
#include <string>
#include <iterator>
#include <algorithm>
const std::string fileName{ "unique.text" };
int main() {
// Open the source file and check, if it could be opend and there is no failure
if (std::ifstream sourceFileStream(fileName); sourceFileStream) {
// Read all words (everything delimited by a white space) into a set
std::set words(std::istream_iterator<std::string>(sourceFileStream), {});
// Now we have a set with all unique words. Show this on the screen
std::copy(words.begin(), words.end(), std::ostream_iterator<std::string>(std::cout, "\n"));
}
// If we could not open the source file
else {
std::cerr << "\nCould not open file '" << fileName << "'\n";
}
return 0;
}

Unable to read text file with boolean grid into vectors of vectors

I have a text file which consists of boolean grid like structure as shown. Now, I am trying to read the text file into a vector<vector<bool>> grid. But I am unable to do so. My code is exiting without any error and execution is not moving inside the while loop.
Text file has below sample:
00000000000000001111111110000
000000100000000010100000100
0000000000000000111111111000
00000000000000011111111111000
0001000000000011111111111110
00000000000000011000000011000
00000000000000100010001000100
00000000000000100000100000
00100011111111111111111001110
00000000000011111000100000001
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <sstream>
using namespace std;
vector<vector<bool> >read_grid(const string &filename)
{
vector<vector<bool> > gridvector;
// Open the File
ifstream in(filename.c_str());
string str;
bool tempb;// Check if object is valid
if(!in)
{
cout<< "Cannot open the File : "<<filename<<endl;
return gridvector;
}
// Read the next line from File untill it reaches the end.
while (getline(in, str))
{
istringstream iss(str);
vector<bool> myvector;
while(iss>>tempb)
{
myvector.push_back(tempb);
}
gridvector.push_back(myvector);
}
//Close The File
in.close();
return gridvector;
}
void display_grid(vector< vector<bool> >& grid)
{
// this generates an 8 x 10 grid and sets all cells to ’0’
//vector<vector<bool> >grid(8, vector<bool>(10, 1));// printing the grid
for(int x = 0; x < grid.size(); x++)
{
for(int y = 0;y < grid[x].size();y++)
{
// cout<<grid[x].size()<<'\n';
cout << grid[x][y];
}
cout << endl;
}
cout<<"grid at position [1][2] is: "<< grid[1][2]<<'\n';
}
int main ()
{
const string b_file = "intial_grid.txt";
vector< vector<bool> > grid_copy = read_grid(b_file);
display_grid(grid_copy);
return 0;
}
It is exiting with 'exit status -1'.
String stream returns true on successful read and false on error.
In your case, iss >> tempb will fail as it is expecting a boolean value, i.e, a bit, but instead receives a string of 0s and 1s.
You can check this after first read iss >> tempb,
if (iss.fail()) {
cout << "Failed to read\n";
}
You could instead iterate over the characters individually.
// Read the next line from File untill it reaches the end.
while (getline(in, str))
{
istringstream iss(str);
vector<bool> myvector;
char bit;
while(iss >> bit)
{
myvector.push_back(bit == '1' ? true : false);
}
gridvector.push_back(myvector);
}
The answer is given and accepted. The errors have been mentioned in the comments.
Anyway, I would like to show a "more" C++ approach, using std algorithms.
The idea is that we want to read a line with boolean values. So I designed a new data type, a class, that contains such data and also knows how to read it. In my humble opinion, the data and the methods should be packed in a class.
This will also reduce the lines of code in function main and overall drastically. In the definition of the variable and through the range constructor, all data will be read.
I added additional some debug output, so that the result can be visualized. Of course the access of the data using the index operator [][] will also work.
Please see:
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
#include <sstream>
std::istringstream testData(
R"#(00000000000000001111111110000
000000100000000010100000100
0000000000000000111111111000
00000000000000011111111111000
0001000000000011111111111110
00000000000000011000000011000
00000000000000100010001000100
00000000000000100000100000
00100011111111111111111001110
00000000000011111000100000001
)#");
// We want to have a data type for one line with boolean values in a string
struct Line {
// We overwrite the extractor operator >> . With that we can easily read a complete line
friend std::istream& operator >> (std::istream& is, Line& l) {
std::string line{}; l.lineOfBool.clear(); getline(is, line);
std::transform(line.begin(), line.end(), std::back_inserter(l.lineOfBool), [](const char c) { return (c == '1') ? true : false; });
return is; }
// Type cast operator to expected value
operator std::vector<bool>() const { return lineOfBool; }
// The data
std::vector<bool> lineOfBool{};
};
int main()
{
// Define the variable that will hold all bool data of the complete file. The range constructor will read the file
std::vector<std::vector<bool>> fileAsStrings{std::istream_iterator<Line>(testData),std::istream_iterator<Line>() };
// For debug purposes: Copy all Data to std::cout
std::for_each(fileAsStrings.begin(), fileAsStrings.end(), [](const std::vector<bool> & l) {std::copy(l.begin(), l.end(), std::ostream_iterator<bool>(std::cout, " ")); std::cout << '\n'; });
return 0;
}
Please note: I do read from an istringstream, initilized with a raw string. So, no difference to reading from a file.
Maybe somebody finds this solution helpful.
The error 'exit status -1' is caused to display_grid() function, the components are vector and the access to the vector is verctorVariable.at();
another error is while(iss>>tempb) because your result is all row, your resolve this problem with this code
istringstream iss(str);
vector<bool> myvector;
string value;
iss >> value;
cout << value;
for(char c : value){
cout << "**** debug print: " << c << endl;
myvector.push_back((bool)(c-'0'));
}
gridvector.push_back(myvector);
also, your method display_grid() should be this
void display_grid(vector< vector<bool> >& grid)
{
// this generates an 8 x 10 grid and sets all cells to ’0’
//vector<vector<bool> >grid(8, vector<bool>(10, 1));// printing the grid
for(int x = 0; x < grid.size(); x++)
{
cout<<"addin another elemen";
for(int y = 0;y < grid[x].size();y++)
{
cout<<"addin another elemen";
cout << grid.at(x).at(y);
}
cout << endl;
}
//cout<<"grid at position [1][2] is: "<< grid[1][2]<<'\n';
}
This code return this exit code Process finished with exit code 0

How do I get an input file to read into a string array in C++?

For some reason the full lines from my input file are not reading into the array, only the first word in each line. I am currently using the getline call, but I am not sure why it is not working. Here is the what I have for the call to populate the array. The txt file is a list of songs.
const int numTracks = 25;
string tracks[numTracks];
int count = 0, results;
string track, END;
cout << "Reading SetList.txt into array" << endl;
ifstream inputFile;
inputFile.open("SetList.txt");
while (count < numTracks && inputFile >> tracks[count])
{
count++;
getline(inputFile, track);
}
inputFile.close();
while (count < numTracks && inputFile >> tracks[count])
The >> operator reads a single word. And this code reads this single word into the vector in question.
getline(inputFile, track);
True, you're using getline(). To read the rest of the line, after the initial word, into some unrelated variable called track. track appears to be a very bored std::string that, apparently, gets overwritten on every iteration of the loop, and is otherwise completely ignored.
Your loop is using the operator>> to read the file into the array. That operator reads one word at a time. You need to remove that operator completely and use std::getline() to fill the array, eg:
const int numTracks = 25;
std::string tracks[numTracks];
int count = 0;
std::cout << "Reading SetList.txt into array" << std::endl;
std::ifstream inputFile;
inputFile.open("SetList.txt");
while (count < numTracks)
{
if (!std::getline(inputFile, tracks[count])) break;
count++;
}
inputFile.close();
Or:
const int numTracks = 25;
std::string tracks[numTracks];
int count = 0;
std::cout << "Reading SetList.txt into array" << std::endl;
std::ifstream inputFile;
inputFile.open("SetList.txt");
while ((count < numTracks) && (std::getline(inputFile, tracks[count]))
{
count++;
}
inputFile.close();
Alternatively, consider using a std::vector instead of a fixed array, then you can use std::istream_iterator and std::back_inserter to get rid of the manual loop completely:
class line : public std::string {}
std::istream& operator>>(std::istream &is, line &l)
{
return std::getline(is, l);
}
...
std::vector<std::string> tracks;
std::cout << "Reading SetList.txt into array" << std::endl;
std::ifstream inputFile;
inputFile.open("SetList.txt");
std::copy(
std::istream_iterator<line>(inputFile),
std::istream_iterator<line>(),
std::back_inserter(tracks)
);
inputFile.close();

c++ initializing array storage size

void start ( string fname )
{
string FirstElement;
int count = 0 ;
fstream Infile;
Infile.open( fname.c_str(), ios::in ); // Open the input file
while(!Infile.eof()) // using while to look for the total lines
{
count++;
}
//read to the array
string data_array[]; //initializing an array
for(int i=0; !Infile.eof(); i++){
Infile >> data_array[i]; // storing the value read from file to array
}
//Display the array
// for(int i=1; i<11; i++){
// cout << data_array[i] << endl;
//}
cout << data_array[0] << endl;
cout << count << endl;
return;
}
I have a text files contain values lines by lines
My plan was to use the while loop to do a total count of the lines
and place it in the "string data_array[]" but somehow it doesnt work that way.
anyone can advise me on how can I make it in a way that It can have a flexible storage size going according to the numbers of values in the text files? thanks
For flexible storage as you call it, you may use STL's container, such as std::vector<T> or std::list<T>. Other issues are highlighted in inline comments.
// pass by reference
void start(const std::string& fname)
{
// use std::ifstream, instead of std::fstream(..., std::ios::in);
std::ifstream Infile(fname.c_str());
// prefer std::vector to raw array
std::vector<std::string> data_array;
std::string line;
// read line by line
while (std::getline(Infile, line))
{
data_array.push_back(line); // store each line
}
// print out size
std::cout << data_array.size() << std::endl;
// display the array, note: indexing starts from 0 not 1 !
for(int i = 0; i < data_array.size(); ++i)
{
std::cout << data_array[i] << std::endl;
}
}