This question already has answers here:
How can I read and parse CSV files in C++?
(39 answers)
Closed 5 years ago.
I am a college student and as part of my final project for a c++ class we are assigned to read a csv file that has distance and force data and then find torque from it. The problem that I am running into is how to actually get the data out of the csv file into a workable format. Currently I have been trying to get it into a matrix, to do this though I will need to first determine the size of the csv file as it is supposed to take any size file. This is the format of the data
Case 1,,,,,x_position (m),y_position (m),z_position (m),F_x (N),F_y (N),F_z (N)16.00,5.00,8.00,394.00,-18.00,396.0022.00,26.00,14.00,-324.00,-420.00,429.0028.00,25.00,21.00,73.00,-396.00,-401.006.00,9.00,12.00,-367.00,-137.00,-143.00
Also obviously the different data pieces (distance and forces) need to be put into different vectors or matrices.
This is what I have so far to try to find the number of lines in the file.
ifstream myfile("force_measurements.csv");
if(myfile.is_open()){
string line;
double num=0;
getline(myfile, line);
if(line==""){
cout<<num<<endl;
myfile.close();
}
else{
num++;
}
}
After this works how would you go about putting the data into a matrix? or would a different format be easier? vectors was my other though.
// you need to include the proper headers here
class vec3D:
{
double m_x, m_y, m_z;
public:
void Set(size_t indx, double val)
{
switch(indx)
{
case 0:
m_x = val;
break;
case 1:
m_y = val;
break;
case 2:
m_z = val;
break;
default:
std::cout << "index out of range" << std::endl;
}
}
double magnitude() { return std::sqrt( m_x*m_x + m_y*m_y + m_z*m_y);}
};
int main()
{
std::ifstream my_data_file ( "your_file_here.csv" );
std::vector<std::array<vec3D, 2>> Pos_Forz;
if ( ! my_data_file.is_open())
{
std::cout << "failure to open the file" <<std::endl;
return -1;
}
std::string temp_str;
double arr[6];
std::array<vec3D,2> temp_3Dvec;
while(!my_data_file.eof())
{
for (int i = 0; i<5 ; i++)
{
getline(my_data_file, temp_str, ",");
arr[i] = std::stod(temp_str);
}
getline(my_data_file, temp_str);
arr[5] = std::stod(temp_str);
for(int i = 0; i<2; i++)
{
for (int j=0; j<3; j++)
{
temp_3Dvec[i].set(j, arr[i*3 + j]);
}
}
Pos_Forz.push_back(temp_3Dvec);
}
for(auto e: Pos_Forz)
{
std::cout << " toque = " << (e[0].magnitude() * e[1].magnitude()) <<std::endl;
}
return 0;
}
Fix what need to be fixed, and inspire yourself from this code, also stop asking this kinda of questions here, you need to read the HOW TO of posting
You have multiple questions. Here's something I used for loading items out of a csv. This gets you started, and you can figure out whether further organization of the data is useful. I personally have classes that take a tokenized line and create an instance of themselves with them.
#include <boost/tokenizer.hpp>
typedef vector<string> csvLine;
void aFunction()
{
string line;
vector<csvLine> usedCollection;
ifstream csvFile("myfile.csv", ios::in);
if (!csvFile)
return -1;
while (getline(csvFile, line))
{
vector<string> tokenizedLine;
boost::tokenizer<boost::escaped_list_separator<char> > tk(
line, boost::escaped_list_separator<char>('\\', ',', '\"'));
for (const string& str : tk)
{
tokenizedLine.push_back(str);
}
usedCollection.push_back(tokenizedLine);
}
csvFile.close();
}
And so usedCollection is a collection of csvLines, where each of those is a collection of strings broken up by the separator character.
Related
for a project, I'm trying to use my randomly generated vector to compare to a given CSV file full of int data. My vector is 6 random numbers, I need to read my csv files, and check if those numbers within my vector exist in all of the files.
What is the best way to access my vector one by one, and compare to all files? my code below worked fine when I originally used an array to store the random numbers but after changing over to a vector, it doesnt seem to work.
I'm very new to C++ for context
int csv_reader() {
string line;
vector<int> numbers;
int filecontents = 0;
num_gen(numbers);
std::string path_to_dir = "example/directory/to/csv's";
for( const auto & entry : std::filesystem::directory_iterator( path_to_dir )) {
if (entry.path().extension().string() != ".csv") continue;
ifstream file(entry.path());
if(file.is_open())
{
while(getline(file, line))
{
file >> filecontents;
for(int i = 0; i > numbers.size(); i++)
{
if(filecontents == numbers.at(i))
cout << "success";
else
cout << "doesnt exist";
}
I need to be able to read in (first number is meant to be id number followed by transactions, making bank statement code, d means deposit, w is withdrawal, numbers after are amount):
123 d45.10 d50.45 d198.56 w45.67
345 w34.00 d4.56 w45.13 d23.23 w23.12
639 d1000.34 d1234.56 w34.33 w345.87 w22.13
890 d345.67 d123.67 d45.99 d45.99 w34.77
666 d66.60 d666.66 d6.66 d66.6 d6666.66
and have it sort into different arrays all stored within a struct. I have tried string stream and various other things i thought of, I'm like medium versed in c++, in the first year class to be specific.
This is the code I have so far, The first set of read ins is working properly but I cannot get the second one to work:
#include<iostream>
#include<fstream>
#include<string>
#include<sstream>
using namespace std;
struct PersonAcct {
int acct_num[5];
string name[5];
double acct_bal[5];
};
struct PersonTrans {
int acct_num[5];
double trans[20];
char d_p[20];
};
int main() {
ifstream ifacc("accounts.txt");
PersonAcct p;
if (ifacc.is_open()) {
for (int i = 0; i <= 4; i++) {
ifacc >> p.acct_num[i];
ifacc >> p.name[i];
ifacc >> p.acct_bal[i];
}
}
ifacc.close();
ifstream iftrans;
iftrans.open("transactions.txt");
PersonTrans q;
string line,line2,line3,line4,line5;
if (iftrans.is_open()) {
int counter = 0;
while (getline(iftrans,line)) {
cout << line << endl;
counter++;
}
}
return 0;
}
Any help would be much appreciated! As I said before I am pretty new in retrospect to most of you on here so please be detailed or explain it for someone a bit daft in this subject, as I prob could be considered. I thank you and wish you a happy early holiday season!
If I understand you correct, you need to parse different words in different lines. You should be able to get this done easily with std::stringstream.
e.g.
...
iftrans.open("transactions.txt");
if (iftrans.is_open())
{
int counter = 0;
string line;
while (getline(iftrans, line)) // iterate through lines
{
int id;
string word;
stringstream ss(line);
ss >> id; // first word is the ID
while (ss >> word) // iterate though words of current line
{
switch (word[0]) // a word starts with either `w` or `d`
{
case 'w':
{
// remaining characters represent a valid double
double const val = stod(word.substr(1));
// process withdrawal
// ...
break;
}
case 'd':
{
double const val = stod(word.substr(1));
// process deposit
// ...
break;
}
default: break; // error?
}
}
counter++;
}
}
You may need to do additional error handling if the commented assumptions are not guaranteed to be valid always.
So I probably implemented it stupidly but here's what I thought you should do. Since the first thing will always be an ID I added that to acct_num;
Next I have a while loop for the line, I create a new string stream (Probably bad form, unsure) using a substring of everything after the first letter. Then I check the first letter of each transaction whether or not its a d or a w and put them into arrays. I had two counters for the w and d arrays. If they were vectors this wouldn't be necessary.
I wasn't sure what your original struct meant so I just created an array for deposits and withdrawals.
#include<iostream>
#include<fstream>
#include<string>
#include<sstream>
using namespace std;
struct PersonTrans {
int acct_num[5];
double deposits[20];
double withdrawals[20];
};
int main() {
ifstream iftrans;
iftrans.open("transactions.txt");
PersonTrans q;
if (iftrans.is_open()) {
int i = 0;
int d = 0;
int w = 0;
string line;
while (getline(iftrans,line)) {
stringstream in(line);
string tmp;
int idNumber;
in >> idNumber;
q.acct_num[i] = idNumber;
while(in >> tmp) {
double value;
std::stringstream transaction(tmp.substr(1));
transaction >> value;
if (tmp[0] == 'd'){
q.deposits[d] = value;
d++;
}
else if (tmp[0] == 'w'){
q.withdrawals[w] = value;
w++;
}
}
i++;
}
}
for(int i = 0; i < 20; i++){
cout << q.deposits[i] << endl;
}
return 0;
}
I am quite new to c++ programming and data structures and really need some help. I am working on an assignment where I have a text file with 100 lines and on each line there is an item, a status(for sale or wanted), and a price. I need to go through the text file and add lines to an array of structs and as I add lines I need to compare the new information with the previously submitted information. If there is a line that is wanted and has a price higher than a previously input item that is for sale then the item would be removed from the struct and the array of structs shifted.
The place that I am having trouble is in actually shifting all the structs once a line that satisfies the condition is found.
My issue is that when I try to shift the array of structs using the second for loop nothing happens and I just get null structs and nothing seems to move.
Please if you guys can offer any help it would be greatly appreciated.
Below is the code of the text file and my current code.
#include<iostream>
#include<fstream>
#include <string>
#include <algorithm>
#include <sstream>
using namespace std;
struct items
{
string type;
int status;
int price;
} itemArray [100];
int main(int argc, char *argv[]) {
int x = -1;
//int chickenCount = 0;
int counter = 0;
int itemsSold = 0;
int itemsRemoved = 0;
int itemsForSale = 0;
int itemsWanted = 0;
string itemType;
int itemStatus = 0;
int itemPrice = 0;
int match = 0;
ifstream myReadFile( "messageBoard.txt" ) ;
std::string line;
//char output[100];
if (myReadFile.is_open()) {
while (!myReadFile.eof()) {
getline(myReadFile,line); // Saves the line in STRING.
line.erase(std::remove(line.begin(), line.end(), ' '), line.end());
//cout<<line<<endl; // Prints our STRING.
x++;
std::string input = line;
std::istringstream ss(input);
std::string token;
while(std::getline(ss, token, ',')) {
counter++;
//std::cout << token << '\n';
if (counter>3){
counter =1;
}
//cout << x << endl;
if (counter == 1){
itemType = token;
//cout<< itemType<<endl;
}
if (counter == 2){
if (token == "forsale"){
itemStatus = 1;
//itemsForSale++;
}
if (token == "wanted"){
itemStatus = 0;
//itemsWanted++;
}
//cout<< itemStatus<<endl;
}
if (counter == 3){
itemPrice = atoi(token.c_str());
//cout<< itemPrice<<endl;
}
//cout<<"yo"<<endl;
}
if (x >= 0){
for (int i = 0; i<100;i++){
if (itemArray[i].type == itemType){
//cout<<itemType<<endl;
if(itemArray[i].status != itemStatus){
if (itemArray[i].status == 1){
if(itemPrice>=itemArray[i].price){
itemsSold++;
match =1;
//itemArray[i].type = "sold";
for (int j=i; j<100-1;j++){
//cout<<j<<endl;
itemArray[j].type = itemArray[j+1].type;
itemArray[j].status = itemArray[j+1].status;
itemArray[j].price = itemArray[j+1].price;
}
i =i-1;
break;
}
}
if (itemArray[i].status == 0){
if(itemArray[i].price>=itemPrice){
itemsSold++;
match = 1;
//itemArray[i].type = "sold";
for (int j=i; j<100-1;j++){
//cout<<j<<endl;
itemArray[j].type = itemArray[j+1].type;
itemArray[j].status = itemArray[j+1].status;
itemArray[j].price = itemArray[j+1].price;
}
i=i-1;
break;
}
}
}
}
}
}
if (counter == 3 && match == 0){
itemArray[(x)].type = itemType;
itemArray[(x)].status = itemStatus;
itemArray[(x)].price = itemPrice;
}
match = 0;
// cout << itemArray[x].type << " " << itemArray[x].status<<" "<<itemArray[x].price<<endl;
}
for(int i=0;i<100;i++){
cout<<itemArray[i].type<< " "<<itemArray[i].status<<" "<<itemArray[i].price<<endl;
}
//cout<<itemArray[1].price<<endl;
cout << itemsSold<<endl;
}
myReadFile.close();
return 0;
}
text file: https://drive.google.com/file/d/0B8O3izVcHJBzem0wMzA3VHoxNk0/view?usp=sharing
Thanks for the help
I see several issues in the code, but without being able to test it, I think the main problem is that you always insert new elements at position 'x' which correspond to the currently line read from the file, without taking into account any shift of elements done. You should insert the new element at the first empty slot (or just overwrite the old element instead of shifting everything).
An other issue is that you do not initialize the status and price in your array.
The best way would be to rewrite the code by using more standard C++ features, for example:
replace the items structure by a class with a constructor defining default values
use object copy (there is no need to copy a struct element by element)
use standard C++ containers like a list (see http://www.cplusplus.com/reference/list/list/) which has insert and erase methods
I would really need your help on this one and I hope I'll get some clue about my compiler error.
The problematic piece of my code:
char user_ch;
do {
user_ch=_getch(); // i changed it from getch() to fix the previous error, didn't help it seems
switch (user_ch) {
case '1': response='1'; break;
case '3': response='3';
}
} while (response!='1'||response!='3');
Compiler error (what's peculiar it's 'build' error instead of 'debug' error):
error C2248: 'std::basic_ios<_Elem,_Traits>::basic_ios' : cannot access private member declared in class 'std::basic_ios<_Elem,_Traits>'
Compiler refers to this piece of code in fstream file:
private:
_Myfb _Filebuffer; // the file buffer
};
As someone pointed out I'm posting my usage of fstream functions and objects.
My functions parsing settings.txt file
bool read_bool(ifstream file, int verse) {
string temp_var;
for (int i=0; i<verse; i++)
getline(file, temp_var);
if (temp_var=="true") return true;
else return false; }
int read_int(ifstream file, int verse) {
string temp_var;
for (int i=0; i<verse; i++)
getline(file, temp_var);
return stoi(temp_var); }
t_direction read_t_dir(ifstream file, int verse) {
char temp_var;
for (int i=0; i<verse; i++)
file.get(temp_var);
t_direction pre_return;
switch (temp_var) {
case '1': pre_return=to_mother; break;
case '2': pre_return=to_foreign; break;
case '3': pre_return=rndom;
}
return pre_return; }
string read_string(ifstream file, int verse) {
string temp_var;
for (int i=0; i<verse; i++)
getline(file, temp_var);
return temp_var; }
size_t lines_count(ifstream if_file) {
size_t a=0;
string temp_str;
while (getline(if_file, temp_str))
++a;
return a; }
bool add_mistake(ofstream file, string mistake, string to_trans, string target) {
file << "Original: " << to_trans << "\nShould be: " << target;
file << "\nYour response: " << mistake;
file << "\n---------------------\n";
return true; }
For error-security sake i've never opened or closed fstream object inside a function.
// stream from file and tokenize
// SYNTAX FOR FILE (each line): word,word>word,word,word
words_input.open(FILE_NAME);
string buffer_line, token;
for (size_t i; i<number_of_lines; i++) {
getline(words_input, buffer_line);
istringstream language_split(buffer_line);
vector<string> container(2);
while (getline(language_split, token, '>')) // split languages
container.push_back(token); // hard coded to ignore possible elements 3, 4, 5...
istringstream synonym_source_split(container.at(0));
while (getline(synonym_source_split, token, ',')) // first language synonyms
source_words[i].push_back(token);
istringstream synonym_target_split(container.at(1));
while (getline(synonym_target_split, token, ',')) // second language synonyms
target_words[i].push_back(token);
}
words_input.close();
Thanks for any help!
Your issue is in this part of the code:
string read_string(ifstream file, int verse) {
string temp_var;
for (int i=0; i<verse; i++)
getline(file, temp_var);
return temp_var;
}
size_t lines_count(ifstream if_file) {
size_t a=0;
string temp_str;
while (getline(if_file, temp_str))
++a;
return a;
}
Both of these functions take as input a parameter of type ifstream. Since you're not taking in the ifstream by reference, when you call this function, C++ will try to initialize if_file to a copy of the ifstream that you passed in as a parameter. This isn't allowed, since ifstreams can't be copied. Unfortunately, you tend to get garbage error messages like the one you showed above instead of something more useful in this case.
To fix this, change your code so that you take the parameters by reference:
string read_string(ifstream& file, int verse) {
string temp_var;
for (int i=0; i<verse; i++)
getline(file, temp_var);
return temp_var;
}
size_t lines_count(ifstream& if_file) {
size_t a=0;
string temp_str;
while (getline(if_file, temp_str))
++a;
return a;
}
That said, there are likely other errors in your code. I would strongly recommend commenting your code as you go and testing pieces incrementally, since as written the code is pretty tough to follow.
This is the drill for Chapter 10 in Programming Principles and Practice Using C++.
The program work with points:
it prompt the user to input (x,y) pairs. They are then stored in a vector of Points called original_points.
the original points are printed to a file
the program then read the file to retrieve the same points, stored in a vector of points called processed_points
the two vectors are compared, if they are not the same, the program throws an error.
The problem is that the processed_points has a size() of 0, that happens only when I use get_vector_points() to get those points. What is wrong with the function?
//put any vector points from ist into points
void get_vector_points(istream& ist, vector<Point>& points)
{
//this function is bad, it doesn't do anything the second time you use it
while(true)
{
Point p;
if( ist >> p)
points.push_back(p);
else return;
}
}
//
void write_to_file(string& path, vector<Point>& v_of_points)
{
//open output file
ofstream ofile(path);
//output results to file
for(Point p : v_of_points)
{
ofile << p <<endl;
}
//close output stream
ofile.close();
}
void read_from_file(string& path, vector<Point>& v_of_points)
{
//open input file
ifstream ifile(path);
//read from file : Here comes trouble
get_vector_points(ifile, v_of_points);
//But no problem if you do the following instead
// while(true)
// {
// Point p;
// if( ifile >> p)
// v_of_points.push_back(p);
// else break;
// }
}
//read point from specified istream ist, format:(0,0)
//output points from specified ostream ost, format:(0,0)
void points_drill(string path)
{
//read from console a vector of points
vector<Point> original_points;
get_vector_points(cin, original_points);
//write the same vector to file
write_to_file(path,original_points);
//read the same vector from file, but call it processed
vector<Point> processed_points;
read_from_file(path,original_points);
//they should be the same
for (int i= 0; i < original_points.size(); i++)
{
if (original_points.size()!=processed_points.size())
throw runtime_error("Size Mismatch"); //error here and proccesed_point has size of 0
if (original_points[i]!=processed_points[i])
throw runtime_error("something is wrong!");
}
}
Note that I'm using a custom Point. Full code is available at http://pastebin.com/ZvfcZxf3
Any comment on the coding style/readability is appreciated.
The call
read_from_file(path,original_points);
is reading into the vector original_points, not processed_points
You should try a different way to read in the file:
void get_vector_points(istream& ist, vector<Point>& points)
{
std::string line;
std::string first, second;
while(std::getline(ist,line))
// this should get every line in the file as a string.
// if the formatting of the file is 2 doubles per line.
// You will need to do the parsing yourself by grabbing each value
{
// example first line: 123 321
first = line.split[0]; // this is not a real function this is just Psudo code
//first = "123"
second = line.split[1];// for parsing text and splitting into 2 doubles
// second = "321"
Point p;
p.x = atoi(first); // atoi is = ascii to int. Makes a string intager into a
p.y = atoi(second);// actual int data type
// p.x = 123 p.y = 321
points.push_back(p)
else return;
}
}
Also, your function get_vector_points will put the input stream to a fail state. You might check EOF and read delimiters (white spaces) to avoid it.
Here with integers:
#include <iostream>
#include <sstream>
#include <vector>
std::istream& get_integers(std::istream& stream, std::vector<int>& integers)
{
int n;
// Read integers and trailing white spaces.
while( ! stream.eof() && stream >> n) {
integers.push_back(n);
stream >> std::ws;
}
return stream;
}
int main()
{
std::istringstream input(" 1 2 3 ");
std::vector<int> integers;
// Read and test the result:
if( ! get_integers(input, integers)) std::cout << "Failure\n";
else {
for(int i : integers)
std::cout << i;
std::cout << '\n';
}
}