Save a Struct Vector into a Tab delimited Text File - c++

I'm reading a 2 to 4 gb .txt file and then I manipulate some of the data and want to save my struct vector as a tab delimited .txt file. I read some of the other questions but still not clear to me how I'm going to do it in my program.
So my question is: How to save the Input vector results as a tab delimited .txt file?
Below is my code:
#include <iostream>
#include <sstream>
#include <string>
#include <fstream>
#include <vector>
#include <cstdio>
using namespace std;
struct Input_Spec {
std::string Data;
std::string Ativo;
int Buy_Sell;
double Sequencia;
double Id;
int Event;
std::string Hr_Priority;
double Priority;
double Price;
double Qtd_Total;
double Qtd_Traded;
std::string Data_Order;
std::string Data_Time_Order;
std::string State_Of_Order;
std::string Condition_Of_Order;
double Broker;
};
void split(const std::string &s, char delim, std::string elems[])
{
std::stringstream ss(s);
std::string item;
long i = 0;
while (std::getline(ss, item, delim))
{
elems[i++] = item;
}
}
int main()
{
ifstream infile1("C:\\Teste\\Teste.txt");
ofstream output("output.txt");
string word;
string columns[16];
string line;
int row=0;
long c=0;
long filescol=0;
for (int i = 0; std::getline(infile1, word); ++i)
{
row++;
}
//cout<<row;
infile1.close();
ifstream infile("C:\\Teste\\Teste.txt");
vector<Input_Spec> Input(row);
while( getline(infile, line))
{
split(line,';', columns);
if (columns[0]!="")
{
Input[filescol].Data =columns[0];
Input[filescol].Ativo =columns[1];
Input[filescol].Buy_Sell = stoi(columns[2]);
Input[filescol].Sequencia = stod(columns[3]);
Input[filescol].Id = stod(columns[4]);
Input[filescol].Event = stoi(columns[5]);
Input[filescol].Hr_Priority = columns[6];
Input[filescol].Priority = stod(columns[7]);
Input[filescol].Price = stod(columns[8]);
Input[filescol].Qtd_Total = stod(columns[9]);
Input[filescol].Qtd_Traded = stod(columns[10]);
Input[filescol].Data_Order = columns[11];
Input[filescol].Data_Time_Order = columns[12];
Input[filescol].State_Of_Order = columns[13];
Input[filescol].Condition_Of_Order = columns[14];
Input[filescol].Broker = stod(columns[15]);
filescol++;
c++;
}
if (c>(999))
{
break;
infile.close();
return 0;
}
}
infile.close();
return 0;
}

Here's a fragment:
ofstream output ("output.txt");
output << Input[filescol].Data << '\t';
output << Input[filescol].Ativo << '\t';
output << Input[filescol].Buy_Sell << '\t';
//...
output << Input[filescol].Broker << '\n';
Is this what you are talking about?

At first, please let me give you some hints on your code: You don't need to count all lines of the input file and you don't need to reserve memory for all items in your vector beforehand. You can use the push_back() function to add items to the vector. This saves you one iteration on the input file.
I put this improvement into the main() function below. I also expanded a little bit on the answer by #ThomasMatthews, so that you can see how to loop over the vector in order to save the data in it:
int main()
{
ifstream infile("C:\\Teste\\Teste.txt");
ofstream output("C:\\Teste\\output.txt");
string line;
string columns[16];
vector<Input_Spec> Input;
Input_Spec oneInput;
while (getline(infile, line))
{
split(line, ';', columns);
if (!columns[0].empty())
{
oneInput.Data = columns[0];
oneInput.Ativo = columns[1];
oneInput.Buy_Sell = stoi(columns[2]);
oneInput.Sequencia = stod(columns[3]);
oneInput.Id = stod(columns[4]);
oneInput.Event = stoi(columns[5]);
oneInput.Hr_Priority = columns[6];
oneInput.Priority = stod(columns[7]);
oneInput.Price = stod(columns[8]);
oneInput.Qtd_Total = stod(columns[9]);
oneInput.Qtd_Traded = stod(columns[10]);
oneInput.Data_Order = columns[11];
oneInput.Data_Time_Order = columns[12];
oneInput.State_Of_Order = columns[13];
oneInput.Condition_Of_Order = columns[14];
oneInput.Broker = stod(columns[15]);
Input.push_back(oneInput);
}
}
// ----------------------
// Modify your data here.
// ----------------------
for(vector<Input_Spec>::const_iterator it = Input.begin(); it != Input.end(); it++)
{
output << it->Data << '\t';
output << it->Ativo << '\t';
output << it->Buy_Sell << '\t';
output << it->Sequencia << '\t';
output << it->Id << '\t';
output << it->Event << '\t';
output << it->Hr_Priority << '\t';
output << it->Priority << '\t';
output << it->Price << '\t';
output << it->Qtd_Total << '\t';
output << it->Qtd_Traded << '\t';
output << it->Data_Order << '\t';
output << it->Data_Time_Order << '\t';
output << it->State_Of_Order << '\t';
output << it->Condition_Of_Order << '\t';
output << it->Broker << '\n';
}
output.close();
infile.close();
return 0;
}
I guess that more improvements could be done to your code, but this should give you a good start.

Related

Reading and Writing from same file?

i am storing some data in the file but after
if (titlemap.count(words[i]) == 1)
is reached i reopened the file and reading all data in a vector and then storing updated data but
But actually the program is not going into the below loop.
for (int j = 0; j < vec.size(); j++)
Can anyone suggest why is it so? I am very confused and frustrated
// Cmarkup1.cpp : This file contains the 'main' function. Program execution begins and ends there.
//
#include <iostream>
#include"Markup.h"
#include <msxml.h>
#include <ctime>
#include <unordered_map>
#include <cctype>
#include <string>
#include <functional>
#include <algorithm>
#include "functions.h"
#include <map>
#include <fileapi.h>
using namespace std;
int main()
{
// Open the file for parsing.
ofstream wfile("title.txt");
bool check = false;
string delimiter = " ,:,";
int results = 0, pages = 1;
time_t timer;
timer = clock();
CMarkup xmlfile;
unordered_map<string, string> titlemap;
unordered_map<string, string> textmap;
vector <string> words;
xmlfile.Load(MCD_T("simplewiki-latest-pages-articles.xml"));
xmlfile.FindElem();
xmlfile.IntoElem();
int line=0;
while (xmlfile.FindElem(MCD_T("page"))) {
xmlfile.IntoElem();
xmlfile.FindElem(MCD_T("title"));
MCD_STR(title);
title = xmlfile.GetData();
string str(title.begin(), title.end());
transform(str.begin(), str.end(), str.begin(), ::tolower);
split(words, str, is_any_of(delimiter));
for (int i = 0; i < words.size(); i++) {
if (titlemap.count(words[i]) == 1) {
ifstream rfile;
rfile.open("title.txt");
vector<string> vec;
string line;
while (getline(rfile, line)) {
vec.push_back(line);
}
for (int j = 0; j < vec.size(); j++) {
if (words[i] == vec[j]) {
cout << vec[j] <<"Checking"<< endl;
wfile << vec[j] << ",page" << pages << endl;
}
else
wfile << vec[j] << endl;
//wfile.close();
}
}
else {
//wfile.open("title.txt");
keeponlyalphabets(words[i]);
titlemap.insert(make_pair(words[i], words[i]));
wfile << words[i] <<"-page"<<pages<< endl;
++line;
}
}
words.clear();
//cout << str << endl;
//xmlfile.FindElem(MCD_T("text"));
//MCD_STR(text);
//text = xmlfile.GetData();
//string str1(text.begin(), text.end());
//transform(str1.begin(), str1.end(), str1.begin(), ::tolower);
//str1 = keeponlyalphabets(str1);
//removestopwords(str1);
//textmap.insert(make_pair(str1, str1));
//cout << str1 << endl;
if (pages > 100)
break;
pages++;
xmlfile.OutOfElem();
}
wfile.close();
// for (auto it : titlemap)
// cout << it.first << endl;
cout << "Total lines are as: "<<line << endl;
/*string input;
cout << "press s to seach the data" << endl;
getline(cin, input);
if (input == "s") {
string key;
cout << "Enter Key" << endl;
cin >> key;
transform(key.begin(), key.end(), key.begin(), ::tolower);
size_t temp;
cout << endl;
for (auto it = data.begin(); it != data.end(); it++) {
//temp = it->first.find(key);
//cout << temp;
if (it->first.find(key) != std::string::npos) {
cout << it->second << endl;
results++;
}
}
}
else
cout << "Invalid Character Exiting....." << endl;
timer = clock() - timer;
cout << "Total time taken by the process is: " << (float)timer / CLOCKS_PER_SEC << endl;
cout << " Total Results : " << results << endl;
*/
return 0;
}
You have separate streams opened against the file, with separate buffers on each. writeing to a file only actually writes to disk infrequently (typically when a buffer fills, which may take a while for small writes, and always just before the file is closed). So when you re-open the file for read, it won't see anything still stuck in user-space buffers.
Just add:
wfile.flush()
prior to opening for read, to ensure the buffers are flushed to disk and available to the alternate handle.

string equal doesn't work c++

I have been struggling with comparing two strings which I read from files, "one" & "two" both have the same words (e.g. salt) but it doesn't return "Equal". I have also used == but it made no difference.
#include <iostream>
#include <cstring>
#include <fstream>
using namespace std;
int main (){
string en[100];
string line;
int i=0;
ifstream fileEn ("hey.txt");
if (fileEn.is_open()){
while (!fileEn.eof()){
getline(fileEn,line);
en[i]=line;
i++;
}
}
fileEn.close();
string fa[100];
string line1;
i=0;
ifstream fileFa ("hey1.txt");
if (fileFa.is_open()){
while (!fileFa.eof()){
getline(fileFa,line1);
fa[i]=line1;
i++;
}
}
fileFa.close();
ifstream Matn("matn.txt");
string matn[100];
if(Matn.is_open()){
for(int i = 0; i < 100; ++i){
Matn >> matn[i];
}
}
Matn.close();
string one = en[0];
string two = matn[0];
cout << one << " " << two;
if(one.compare(two) == 0){
cout << "Equal";
}
}
I suggest adding some debugging output to your program:
while (!fileEn.eof()){
getline(fileEn,line);
// Debugging output
std::cout << "en[" << i << "] = '" << line << "'" << std::endl;
en[i]=line;
i++;
}
and
for(int i = 0; i < 100; ++i){
Matn >> matn[i];
// Debugging output
std::cout << "matn[" << i << "] = '" << matn[i] << "'" << std::endl;
}
Hopefully you can see what the problem is by looking at the output.
In addition, please note that use of while (!fileEn.eof()){ ... } is not correct. See Why is iostream::eof inside a loop condition considered wrong?.
I suggest changing that loop to:
while (getline(fileEn,line)) {
// Debugging output
std::cout << "en[" << i << "] = '" << line << "'" << std::endl;
en[i]=line;
i++;
}
Similarly, don't assume that Matn >> matn[i] is successful. I suggest changing that loop to:
for(int i = 0; i < 100; ++i) {
std::string s;
if ( !(Matn >> s) )
{
// Read was not successful. Stop the loop.
break;
}
matn[i] = s;
// Debugging output
std::cout << "matn[" << i << "] = '" << matn[i] << "'" << std::endl;
}

ifstream::read not working?

I am trying to read from a .csv file. There are two functions below, one for writing and one for reading.
The file contains a simple table:
date,first,second
1 a one
2 b two
3 c three
4 c four
For some reason, the statement while(file_stream.read(&c,1)); does not read anything. It stops at the first character and I'm dumbfounded as to why. Any clues?
#include <iostream>
#include <sstream>
#include <fstream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <string>
#include <cstdlib>
using namespace std;
std::string filename;
std::string line_string;
ifstream file_stream;
stringstream ss;
vector< vector<string> > vec;
char c;
void read_file()
{
filename = "test.csv";
cout << filename << endl;
file_stream.open(filename.c_str(),ios::out|ios::binary);
if(file_stream.fail())
{
cout << "File didn't open" << endl;
return;
}
if(file_stream.is_open())
cout << "file opened" << endl;
while(file_stream.read(&c,1)); // this isn't working
{
cout <<"char c is: " << c;
ss << noskipws << c;
}
file_stream.close();
cout << "string is: " << ss.str() << endl;
//get each line
int counter = 0;
vector<string> invec;
while(getline(ss,line_string,'\n'))
{
string header_string;
stringstream header_stream;
header_stream << line_string;
while(getline(header_stream, header_string,','))
{
invec.push_back(header_string);
}
invec.push_back(header_string);
vec.push_back(invec);
invec.clear();
counter++;
}
}
void test_output()
{
for(int i = 0; i < vec.size();i++)
{
for(int in = 0; in < vec[0].size(); in++)
cout << vec[i][in] << " ";
cout << endl;
}
}
int main()
{
read_file();
test_output();
}
Look very very carefully at the line that is not working:
while(file_stream.read(&c,1)); // this isn't working
{
cout <<"char c is: " << c;
ss << noskipws << c;
}
The ; character at the end of the while statement does NOT belong! You are running a no-body loop that does not terminate until read() fails, and THEN your code enters the bracketed block to output the last character that was successfully read (if any).
You need to remove that erroneous ; character:
while(file_stream.read(&c,1)) // this works
{
cout <<"char c is: " << c;
ss << noskipws << c;
}
Now, the real question is - why are you reading the input file character-by-character into a std::stringstream in the first place? You can use std::getline() with the input std::ifstream directly:
#include <iostream>
#include <sstream>
#include <fstream>
#include <vector>
#include <string>
std::vector< std::vector<std::string> > vec;
void read_file()
{
std::string filename = "test.csv";
std::cout << filename << std::endl;
std::ifstream file_stream;
file_stream.open(filename.c_str(), ios::binary);
if (!file_stream)
{
std::cout << "File didn't open" << std::endl;
return;
}
std::cout << "file opened" << std::endl;
//get each line
std::vector<std::string> invec;
std::string line;
int counter = 0;
if (std::getline(file_stream, line))
{
std::istringstream iss(line);
while (std::getline(iss, line, ','))
invec.push_back(line);
vec.push_back(invec);
invec.clear();
++counter;
while (std::getline(file_stream, line))
{
iss.str(line);
while (iss >> line)
invec.push_back(line);
vec.push_back(invec);
invec.clear();
++counter;
}
}
}
void test_output()
{
if (!vec.empty())
{
for(int in = 0; in < vec[0].size(); ++in)
std::cout << vec[0][in] << ",";
std::cout << std::endl;
for(int i = 1; i < vec.size(); ++i)
{
for(int in = 0; in < vec[i].size(); ++in)
std::cout << vec[i][in] << " ";
std::cout << std::endl;
}
}
}
int main()
{
read_file();
test_output();
}

Find specific lines in text document

I want to create small program to understand things I need better.
This code can write words to text document, new line under previous in sequential order and keep lines there after starting program again.
Now before adding a new word or phrase to the file, I want to find if the word already exists in my document, if exist, don't add it, but get exist equal one on output, read it from file, and main thing here is somehow also find line under or above current exist line. For example: if exist line index is 3, I want to see +1 line 4 or -1 line 2. If new word doesn't exist in text document just add it.
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
std::ofstream outfile("doc.txt", std::ios_base::app);
int main()
{
std::string t;
for (int i = 0; i < 10; i++)
{
cout << "Add new phrase: " << endl;
std::getline(std::cin, t);
cout << t << endl;
outfile << t << std::endl;
}
_getch();
return 0;
}
EDIT:
using namespace std;
std::ofstream outfile("doc.txt", std::ios_base::app);
int main()
{
int length = 100;
std::ifstream infile("doc.txt", std::ifstream::in);
infile.seekg(0, infile.end);
size_t len = infile.tellg();
infile.seekg(0, infile.beg);
char *buf = new char[len];
infile.read(buf, length);
infile.close();
std::string writtenStr(reinterpret_cast<const char *>(buf), len);
std::string t;
for (int i = 0; i < 10; i++)
{
std::getline(std::cin, t);
if (writtenStr.find(t) != std::string::npos)
{
cout << "Line [" << t << "] exist." << endl;
}
else
{
cout << "Line [" << t << "] saved." << endl;
writtenStr += t;
outfile << t << std::endl;
}
}
_getch();
return 0;
}
I'd read the file into a string when the program starts. Then, check the string for the phrase each time i want to add a new word. If the string doesn't contain the phrase, add it to the string and the file, and a delimiter of your choice if desired. For example:
int main()
{
// Read existing file into a string
std::ifstream infile("doc.txt", std::ifstream::in);
infile.seekg(0, infile.end);
size_t len = infile.tellg();
infile.seekg(0, infile.beg);
char *buf = new char[len];
infile.read(buf,length);
infile.close();
std::string writtenStr(reinterpret_cast<const char *>(buf), len);
// Open file for output
std::ofstream outfile("doc.txt", std::ios_base::app);
std::string t;
for (int i = 0; i < 10; i++)
{
// Get new phrase
std::getline(std::cin, t);
// Check if phrase is already in file;
if (writtenStr.find(t) == std::string::npos)
{
cout << "Could not add new phrase: " << endl;
cout << t << endl;
cout << "Phrase already exists in file." << endl;
}
else
{
cout << "Add new phrase: " << endl;
cout << t << endl;
writtenStr += t;
outfile << t << std::endl;
}
}
_getch();
return 0;
}

text file contents to array

I have a text file-> info.txt which contains the follow Id,games,amount
info.txt
1,left4dead,50
2,warcraft3,60
I know how to extract the details using vectors with my codes shown below.
stock.h
#ifndef stock_stock_h
#define stock_stock_h
#include <iostream>
class stock {
public:
stock() {
columnOneText = " ";
columnTwoText = " ";
}
stock(std::string columnOneText,
std::string columnTwoText
);
std::string getColumnOne();
std::string getColumnTwo();
void setItemId(std::string columnOneText);
void setItemDescription(std::string columnTwoText);
private:
std::string columnOneText, columnTwoText;
};
#endif
main.cpp
#include "stock.h"
#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
#include <vector>
using namespace std;
stock::stock(string columnOneText,
string columnTwoText)
{
setItemId(columnOneText);
setItemDescription(columnTwoText);
};
string stock::getColumnOne() {
return columnOneText;
}
string stock::getColumnTwo() {
return columnTwoText;
}
void stock::setItemId(string columnOneText) {
this->columnOneText = columnOneText;
}
void stock::setItemDescription(std::string columnTwoText) {
this->columnTwoText = columnTwoText;
}
int main(){
vector<stock> itemDetails;
string line;
string columnOneText;
string columnTwoText;
ifstream readFile("info.txt");
while(getline(readFile,line)) {
stringstream iss(line);
getline(iss, columnOneText,',');
getline(iss, columnTwoText, ',');
//consturctor
stock splitedColumns(columnOneText,
columnTwoText
);
itemDetails.push_back(splitedColumns);
}
readFile.close();
cout << "this is column One in text file" << endl;
for (int i =0; i<itemDetails.size(); i++) {
cout << itemDetails[i].getColumnOne() << " " << endl;
}
cout << "this is column Two in text file" << endl;
for (int i =0; i<itemDetails.size(); i++) {
cout << itemDetails[i].getColumnTwo() << " " << endl;
}
}
what I don't really know is how to extract the details using arrays instead of using vectors.
I have tried this but it doesn't seem to work
string line;
string columnOneText;
string columnTwoText;
string columnOneTextArray[7];
while(getline(readFile,line)) {
stringstream iss(line);
getline(iss, columnOneText,',');
getline(iss, columnTwoText, ',');
for(int i=0; i<8; i++) {
columnOneTextArray[i] = columnOneText;
cout << columnOneTextArray[i];
}
}
You guys might ask why do I want to do it in arrays instead of using vector,
I just curious and exploring how it can be done using arrays.
You problem can be solved in a lot simpler manner by using struct definitions in addition to using vectors (your use of classes is a bit of overkill, IMHO):
#include <fstream>
#include <iostream>
#include <cstdlib>
#include <vector>
#include <sstream>
//this utilizes a more idiomatic naming convention as opposed to `columnX`
typedef struct Stock {
int id;
std::string games;
int amount;
} Stock;
//Syntactic sugar for easier output
std::ostream& operator << (std::ostream& in, const Stock& stock) {
in << stock.id << " " << stock.games << " " << stock.amount;
return in;
}
int main() {
std::string filename = "info.txt";
std::fstream ifile;
std::vector <Stock> inventory;
Stock stock_t;//a temporary Stock variable
std::string temp;
ifile.open(filename.c_str(), std::ios::in);
if (!ifile.is_open()) {
std::cerr << "There was a problem opening the input file: \"" << filename << "\"\n";
exit(1);
}
while (ifile >> temp) {
std::istringstream iss(temp);
int column = 0;
//break each constituent line by using the comment as a delimiter:
while(std::getline(iss, temp, ',')) {
if (column == 0) {
stock_t.id = std::atoi(temp.c_str());
}
else if (column == 1) {
stock_t.games = temp;
}
else if (column == 2) {
stock_t.amount = std::atoi(temp.c_str());
}
++column;
}
inventory.push_back(stock_t);
}
for (int i = 0; i < inventory.size(); ++i) {
std::cout << inventory[i] << "\n";
}
ifile.close();
return 0;
}
Which outputs:
1 left4dead 50
2 warcraft3 60