How to properly read data from CSV file in C++ - c++

My input file userinfo.csv contains username and password in this format username,password shown below.
frierodablerbyo,Rey4gLmhM
pinkyandluluxo,7$J#XKu[
lifeincolorft,cmps9ufe
spirginti8z,95tcvbku
I want to store all the usernames and passwords in
vector<string> usernames;
vector<string> passwords;
I've never used C++ for file handling, only python
EDIT1
#include <bits/stdc++.h>
using namespace std;
int main()
{
fstream myfile;
myfile.open("small.csv");
vector<string> data;
vector<string> usernames, passwords;
while(myfile.good()){
string word;
getline(myfile, word, ',');
data.push_back(word);
}
for(int i=0; i<8; i=i+2){
usernames.push_back(data[i]);
}
for(int i=1; i<8; i=i+2){
passwords.push_back(data[i]);
}
}
I know above code is bad, how can I improve it because my actual csv file contains 20000 rows.

The code snipplet already posted is fine, but keep in mind that the CSV separators are locale-dependent, e. g. for US its a ',', for Germany it would be ';' and so on. Also if you have text sections in your CSV which might contain one of those characters, you have to check for opening and closing quotation marks.
The most easy thing to do is to use a ready-made library for parsing CSVs, for example https://github.com/d99kris/rapidcsv.

You can try something like this
std::vector <std::pair<std::string, std::string>> vec_credentials;
std::ifstream is("credentials.csv");
if(is.is_open())
{
std::string line;
while(getline(is, line))
{
std::stringstream ss(line);
std::string token;
std::vector <std::string> temp;
// this is good if in the future you will have more than 2 columns
while(getline(ss, token, ','))
{
temp.push_back(token);
}
vec_credentials.push_back(std::make_pair(temp[0], temp[1]));
}
is.close();
}

Related

How to read from a text file and split it into values in C++

This is my text file (mytext.text):
rho_0,10
kp_0,8
Beta_kp,6
x_min,5
x_max,8
y_min,9
y_max,5
z_min,4
z_max,7
I want to read from this text file line by line, and store each value in the parameter at the same line.
For example, for the first line, store 10 in rho_0.
I have written this code:
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main ()
{
string line;
ifstream myfile("mytext.txt");
if (myfile.is_open())
while (getline(myfile, line))
{
cout << line << endl;
}
}
But I don't think it will save the value for the corresponding parameter.
I know that I should split each line by delimiter, and then convert string to double (float), but I don't know how to implement it for each line.
You'll want to use a map data structure of some sort to store parameter values. You'll probably want std::unordered_map for this. Like #user4581301 said, you can use std::getline with a specific delimiter, like a comma.
std::unordered_map<std::string, float> params;
std::ifstream myfile("mytext.txt");
std::string param_name;
float param_value;
while (std::getline(myfile, param_name, ',')) {
myfile >> param_value;
myfile.get(); // discard newline
params.insert({ param_name, param_value });
}
This code doesn't handle invalid input, so you can add error handling if you want.

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

Strange result when editing file in C++

For a couple of weeks now, I have been developing a random class generator for the Xbox game Call of Duty: Modern Warfare 3. In this game, different weapons have different levels, which increase as you use the weapon more. I am storing the weapons and their levels in a text file, which store the data on separate lines with the format
weapon-weapon_level
So the M4A1 with weapon level 8 would look like:
m4a1-8
(The weapons are all in lowercase with no punctuation or spaces).
I have already written methods for creating the file and reading the file, but I want a method to edit the file, so the user enters the weapon whose level they want to change, then the new level. Here's what I have so far: (The file is called "weaponlevels.txt")
void WeaponLevelFile::editFile()
{
string line;
string weapon;
string weaponent;
string weaponlevel;
string temp;
cout<<"Please enter the weapon whose level you wish to change. Enter the name in lowercase, with "<<endl;
cout<<"no spaces or punctuation except full stops. E.g. SCAR-L becomes scarl and Barrett .50cal "<<endl;
cout<<"becomes barrett.50cal."<<endl;
cin>>weaponent;
cout<<"Please enter the new weapon level."<<endl;
cin>>temp;
ifstream infile("weaponlevels.txt");
ofstream outfile("weaponlevels.txt");
while (getline(infile, line))
{
istringstream ss(line);
getline(ss,weapon,'-');
if (weapon == weaponent)
{
ss>>weaponlevel;
weaponlevel=temp;
outfile<<weaponlevel<<endl;
infile.close();
outfile.close();
}
}
}
This method does not work however; all it does is wipe the file (so the file is blank). Why does it do this, and what is a better method?
EDIT:
#stardust_'s answer worked the best, but still didn't completely do it. Here is the code:
#include <iostream>
#include <fstream>
#include <sstream>
using namespace std;
int main()
{
string temp;
string line;
string weapon;
string weaponent;
string weaponlevel;
cout<<"enter weapon"<<endl;
cin>>weaponent;
cout<<"enter level"<<endl;
cin>>temp;
ifstream infile("weaponlevels.txt");
std::string in_str((std::istreambuf_iterator<char>(infile)),
std::istreambuf_iterator<char>());
infile.close();
stringstream infile_ss(in_str);
while (getline(infile_ss, line))
{
istringstream ss(line);
getline(ss,weapon,'-');
if (weapon == weaponent)
{
ss>>weaponlevel;
weaponlevel=temp;
infile_ss<<weaponlevel<<endl;
}
}
ofstream outfile("weaponlevels.txt");
outfile << infile_ss.str();
outfile.close();
}
It modifies the right part of "weaponlevels.txt", but doesn't completely do it. if i enter m4a1 as the weapon and 7 as the weapon level, instead of becoming m4a1-7 it becomes:
7
a1-3
After quite a lot of work, here's what worked:
#include <iostream>
#include <fstream>
#include <sstream>
using namespace std;
int main()
{
string temp;
string line;
string weapon;
string weaponent;
string weaponlevel;
cout<<"enter weapon"<<endl;
cin>>weaponent;
cout<<"enter level"<<endl;
cin>>temp;
ifstream infile("weaponlevels.txt");
std::string in_str((std::istreambuf_iterator<char>(infile)),
std::istreambuf_iterator<char>());
infile.close();
stringstream infile_ss(in_str);
ostringstream out;
while (getline(infile_ss, line))
{
istringstream ss(line);
getline(ss,weapon,'-');
out << weapon << '-'; // Write the first part of the line.
if (weapon != weaponent)
{ // Not the correct weapon so just write the original information.
ss >> weaponlevel;
out << weaponlevel << endl;
}
else
{ // Found the desired weapon, change the level.
out << temp << endl;
}
}
I loaded the whole string into an ostringstream and found the weapon within the string.
Have you tried using pointers to search through the file for a specific string to replace? I have yet to write a program that uses this myself, but I know it's pretty common. Otherwise you'll just be overwriting the entire file.
Note that I'm not entirely certain whether you have used pointers in your code for this purpose because, as I stated above, I have yet to use this myself. However, from what I saw, I don't think you did. Just correct me if I'm wrong.
There are many problems with your code. You are opening a file twice. you are closing the ifstreams in a loop while reading them (?). ...
However algorithm wise you can open the file for reading, read the whole thing to a string, close the file, modify the string, open the file for writing, write the string, close the file.
int main()
{
cin>>temp;
ifstream infile("weaponlevels.txt");
std::string in_str((std::istreambuf_iterator<char>(infile)),
std::istreambuf_iterator<char>());
infile.close();
stringstream infile_ss(in_str);
while (getline(infile_ss, line))
{
istringstream ss(line);
getline(ss,weapon,'-');
if (weapon == weaponent)
{
ss>>weaponlevel;
weaponlevel=temp;
infile_ss<<weaponlevel<<endl;
}
}
ofstream outfile("weaponlevels.txt");
outfile << infile_ss.str();
outfile.close();
}
instead of
ifstream infile("weaponlevels.txt");
use
ifstream infile("weaponlevels.txt", ifstream::in)

Reading separated columns in a CSV file in C++ using getLine

I have a program that can successfully read a CSV file. The said CSV file is a list separated by 3 columns. And each column has a comma in between each line. For instance
line 1 --- artist, genre, song
line 2 --- Michael jackson, Pop, thriller
and so on. What I want my program to do is read the first line and to take artist, genre, and song, print those out to the user as options. For instance
"Choose an Option"
1. Artist
2. Genre
3. Song
and then when they select an option it then shows them either all the artists, songs, or genres in the CSV file.
So far I have my program reading the CSV and putting each line in a vector. Here is my code so far ...
#include <iostream>
#include <sstream>
#include <string>
#include <fstream>
#include <vector>
using namespace std;
int main()
{
ifstream infile("music_list.csv");
string line = "";
vector<string> all_words;
cout << "Hello";
while (getline(infile, line))
{
stringstream strstr(line);
string word = "";
while (getline(strstr,word, ','))
{
all_words.push_back(word);
}
for (unsigned i = 0; i < all_words.size(); i++)
{
cout << all_words.at(i)<< "\n";
}
}
system("pause");
return 0;
}
I'm just having trouble figuring out how to have it read the first line, separate each string in the first line that is already separated by a comma and have that then outputted to the user as an option. So in essence I can change artist, genre, song to something like appetizers, dish, drinks in the CSV file.
First you have to read the csv file and store the lines in a vector, You can use this function to do that.
vector<string> readCsvFileContent(const string file)
{
vector<string> buffer;
ifstream configFile;
configFile.exceptions(ifstream::badbit);
try
{
configFile.open(file.c_str(),ifstream::in);
if(configFile.is_open())
{
string line;
while (getline(configFile,line))
{
buffer.push_back(line);
}
configFile.close();
}
}
catch (ifstream::failure e){
throw e;
}
return buffer;
}
Then split the each line entry to 2D vector. for that you can use this function
vector<vector<string>> processCsvList(vector<string> csvList)
{
#define SINGER_CONFIG_COUNT 3 //number of comma separated data suppose to be in one line.
#define DELIMITED_CHAR ","
#define EMPTY_STRING "";
vector<vector<string>> tempList;
string configCell ="";
for(vector<string>::iterator it = csvList.begin(); it != csvList.end(); ++it)
{
if(*it == EMPTY_STRING)
{
continue;
}
stringstream configLine(*it);
vector<string> tempDevice;
for(int i=0; i<SINGER_CONFIG_COUNT; i++)
{
if(getline(configLine,configCell,DELIMITED_CHAR))
{
tempDevice.push_back(configCell);
}else
{
tempDevice.push_back(EMPTY_STRING);
}
}
tempList.push_back(tempDevice);
}
return tempList;
}
I haven't try to compile any of these function, because I do not have environment to do so here. But I think this will help to to think about the direction.
now your data in a 2D vector like excell sheet. So you can access by the index of the inner vector.
You could create a std::map<string,vector<string>> so that you could then store each column of the CSV file from line 2 onwards in the map as a vector of strings, keyed by the text that appears in the column on line 1 of the CSV file.
Then you could present the names of the fields by iterating through the keys of the std::map, which are conveniently stored in alphabetical order.
The task of reading in the first line of the CSV file could be performed by the code you already have, or something more sophisticated that takes into account the quoted fields, etc. that are found in fully-featured CSV files.

is it possible to read from a specific character in a line from a file in c++?

Hey all so I have to get values from a text file, but the values don't stand alone they are all written as this:
Population size: 30
Is there any way in c++ that I can read from after the ':'?
I've tried using the >> operator like:
string pop;
inFile >> pop;
but off course the whitespace terminates the statement before it gets to the number and for some reason using
inFile.getline(pop, 20);
gives me loads of errors because it does not want to write directly to string for some reason..
I don't really want to use a char array because then it won't be as easy to test for the number and extract that alone from the string.
So is there anyway I can use the getline function with a string?
And is it possible to read from after the ':' character?
#include <iostream>
#include <fstream>
#include <string>
#include <cstring>
#include <cstdlib>
using namespace std;
int main()
{
string fname;
cin >> fname;
ifstream inFile;
inFile.open(fname.c_str());
string pop1;
getline(inFile,pop1);
cout << pop1;
return 0;
}
ok so here is my code with the new getline, but it still outputs nothing. it does correctly open the text file and it works with a char array
You are probably best to read the whole line then manipulate the string :-
std::string line;
std::getline(inFile, line);
line = line.substr(19); // Get character 20 onwards...
You are probably better too looking for the colon :-
size_t pos = line.find(":");
if (pos != string::npos)
{
line = line.substr(pos + 1);
}
Or something similar
Once you've done that you might want to feed it back into a stringstream so you can read ints and stuff?
int population;
std::istringstream ss(line);
ss >> population;
Obviously this all depends on what you want to do with the data
Assuming your data is in the form
<Key>:<Value>
One per line. Then I would do this:
std::string line;
while(std::getline(inFile, line))
{
std::stringstream linestream(line);
std::string key;
int value;
if (std::getline(linestream, key, ':') >> value)
{
// Got a key/value pair
}
}