Im learning SDL2 and now im trying to save a game ranking into a .bin file. I have placed the ranking data into a vector. But im unable to save the data. Perhabs it has to do with file size, but im unable to solve that. This is the code that im using now:
class Player {
private:
std::string name, faction, dific;
int points;
public:
Player() {};
virtual ~Player() {};
void addName(std::string s);
void addFacti(std::string s);
void addDific(std::string s);
void addPoint(int p);
std::string getName() const;
std::string getFacti() const;
std::string getDific() const;
int getPoint() const;
bool operator>(const Player& p) const;
};
Player p1; Player p2;//just two examples
//add properties to each object
std::vector<Player>classi;
classi.push_back(p1); classi.push_back(p2);
std::sort(classi.begin(), classi.end(), std::greater<Player>());
//load file
SDL_RWops* rankfile = SDL_RWFromFile("ranking.bin", "r+b");
for (int i = 0; i < classi.size(); ++i) { SDL_RWread(rankfile, &classi[i], sizeof(Player), 1); }
SDL_RWclose(rankfile);
//im able to render the objects
//save file - but it doesnt save anything
rankfile = SDL_RWFromFile("ranking.bin", "w+b");
for (int i = 0; i < classi.size(); ++i) { SDL_RWwrite(rankfile, &classi[i], sizeof(Player), 1); }
SDL_RWclose(rankfile);
Here's an example of how I might serialize a struct containing std::string to/from binary. It doesn't use the SDL functions because I don't use SDL but it wouldn't be difficult to modify if desired.
You may have a different problem since you say your file is empty, and I am concerned that you try and read the file before you write it, but you could try something like this and see if it helps.
#include <iostream>
#include <string>
#include <fstream>
#include <tuple>
template <typename T>
std::ostream &writeBinary(std::ostream &f, T data)
{
return f.write(reinterpret_cast<char *>(&data), sizeof(data));
}
std::ostream &writeBinary(std::ostream &f, const std::string &str)
{
// If file size is a concern you might use a smaller type like uint16_t.
// Just make sure to mirror the change in readBinary.
std::string::size_type sz = str.size();
if (f)
{
f.write(reinterpret_cast<char *>(&sz), sizeof(sz));
}
if (f)
{
f.write(str.data(), str.size());
}
return f;
}
template <typename T>
std::istream &readBinary(std::istream &f, T &data)
{
if (f)
{
f.read(reinterpret_cast<char *>(&data), sizeof(data));
}
return f;
}
std::istream &readBinary(std::istream &f, std::string &str)
{
std::string::size_type sz = 0;
if (f)
{
f.read(reinterpret_cast<char *>(&sz), sizeof(sz));
}
if (f)
{
str.resize(sz);
f.read(str.data(), sz);
}
return f;
}
struct Thing
{
std::string shortString;
int i;
double d;
std::string longString;
Thing()
: i(99)
, d(99.99)
{ }
bool operator==(const Thing &rhs) const
{
return std::tie(shortString, i, d, longString)
== std::tie(rhs.shortString, rhs.i, rhs.d, rhs.longString);
}
bool write(std::ofstream &f)
{
if (!writeBinary(f, shortString))
{
return false;
}
if (!writeBinary(f, i))
{
return false;
}
if (!writeBinary(f, d))
{
return false;
}
if (!writeBinary(f, longString))
{
return false;
}
return true;
}
bool read(std::ifstream &f)
{
if (!readBinary(f, shortString))
{
return false;
}
if (!readBinary(f, i))
{
return false;
}
if (!readBinary(f, d))
{
return false;
}
if (!readBinary(f, longString))
{
return false;
}
return true;
}
};
std::ostream &operator<<(std::ostream &o, const Thing &t)
{
return o << "'" << t.shortString << "'" << ", "
<< t.i << ", " << t.d << ", "
<< "'" << t.longString << "'";
}
int main()
{
Thing t1;
// Shorter string to hopefully fit in any short string optimization buffer in the string.
t1.shortString = "Short";
t1.longString = "Long string that should be long enough to not fit in the SSO buffer.";
t1.i = 42;
t1.d = 42.42;
std::cout << "t1 Before Write: " << t1 << "\n";
std::ofstream out("thing.bin", std::ios::binary);
if (!t1.write(out))
{
std::cout << "Error writing t1!\n";
return -1;
}
out.close();
std::cout << "t1 After Write: " << t1 << "\n";
Thing t2;
std::cout << "t2 Before Read: " << t2 << "\n";
std::ifstream in("thing.bin", std::ios::binary);
if (!t2.read(in))
{
std::cout << "Error reading t2!\n";
return -1;
}
in.close();
std::cout << "t2 After Read: " << t2 << "\n";
std::cout << "t1 == t2: " << std::boolalpha << (t1 == t2) << "\n";
return 0;
}
Related
My issue is my last increment_watch function. I would like to be able modify parts of the Movie class while it is in a vector container. Right now I am only able to grab a specific Movie object and its increment but I am unable to change or modify any of it while it is in a vector. I would like to be able to modify or add +1 to the watched element. Is this at all possible?
EDIT: I have updated the "increment_watched" function taking suggestions from the comments. I have tried to pass by reference the watched variable but the "mov.set_watched" call in the increment_watched function is not taking effect.
#include <iostream>
#include <vector>
#include <string>
class Movie {
friend std::ostream &operator<<(std::ostream &os, const Movie &p);
private:
std::string name;
std::string ratting;
int watched;
public:
Movie() = default;
Movie(std::string name, std::string ratting, int watched)
: name{name}, ratting{ratting}, watched{watched} {}
void increment_watched(std::vector<Movie> vec, std::string name);
bool operator<(const Movie &rhs) const { // always overload
return this->watched < rhs.watched;
}
bool operator==(const Movie &rhs) const {
return (this->name == rhs.name && this->watched == rhs.watched); // always overload
}
void set_name(std::string name) {
this->name = name;
}
std::string getName() {
return name;
}
void set_ratting(std::string ratting) {
this->ratting = ratting;
}
std::string getRatting() {
return ratting;
}
void set_watched(int watched) {
this->watched = watched;
}
int getWatched() {
return watched;
}
};
std::ostream &operator<<(std::ostream &os, const Movie &p) {
os << p.name << " : " << p.ratting << " : " << p.watched;
return os;
}
// template function to display any vector
template <typename T>
void display(const std::vector<T> &lem) {
std::cout << "[ ";
for (const auto &elem: lem)
std::cout << elem << " ";
std::cout << " ]"<< std::endl;
}
// I want to modify this function to increment the "watched" variable by one
void increment_watched(std::vector<Movie> vec, std::string name, int &watched){
watched =+ 1;
for (auto &mov: vec){
if (mov.getName() == name){
std::cout << name << std::endl;
mov.set_watched(watched);
}
}
}
int main() {
std::vector<Movie> vec;
int watched = 1;
Movie p1 {"Star Wars", "PG", 2};
Movie p2 {"Indiana Jones", "PG", 1};
Movie p3 {"Matrix", "PG-13", 5};
vec.push_back(p2);
vec.push_back(p3);
std::cout << p1.getName() << std::endl;
std::cout << p1.getRatting() << std::endl;
p1.set_watched(100);
vec.push_back(p1);
std::cout << p1.getWatched() << std::endl;
display(vec);
increment_watched(vec, "Star Wars", watched);
display(vec);
return 0;
}
Thank you user WhozCraig, this lead me to answering my question!
You response lead the to the correct output. I wanted to change the values and completely over looked passing the vec variable to pass by reference. I knew it was something small that I was over looking
To all those who posted helpful comments to help post better questions on the site, thank you. I am new to StackOverflow. I will review the provided helpful links in order to post better questions in the future. Some commented that I posted the same question twice, I panicked and deleted the post because it was locked, I didnt know what to do so I thought I would start over.
Here is the corrected code:
#include <iostream>
#include <vector>
#include <string>
class Movie {
friend std::ostream &operator<<(std::ostream &os, const Movie &p);
private:
std::string name;
std::string ratting;
int watched;
public:
Movie() = default;
Movie(std::string name, std::string ratting, int watched)
: name{name}, ratting{ratting}, watched{watched} {}
void increment_watched(std::vector<Movie> vec, std::string name);
bool operator<(const Movie &rhs) const { // always overload
return this->watched < rhs.watched;
}
bool operator==(const Movie &rhs) const {
return (this->name == rhs.name && this->watched == rhs.watched); // always overload
}
void set_name(std::string name) {
this->name = name;
}
std::string getName() {
return name;
}
void set_ratting(std::string ratting) {
this->ratting = ratting;
}
std::string getRatting() {
return ratting;
}
void set_watched(int watched) {
this->watched = watched;
}
int getWatched() {
return watched;
}
};
std::ostream &operator<<(std::ostream &os, const Movie &p) {
os << p.name << " : " << p.ratting << " : " << p.watched;
return os;
}
// template function to display any vector
template <typename T>
void display(const std::vector<T> &lem) {
std::cout << "[ ";
for (const auto &elem: lem)
std::cout << elem << " ";
std::cout << " ]"<< std::endl;
}
// I want to modify this function to increment the "watched" variable by one
void increment_watched(std::vector<Movie> &vec, std::string name, int &watched){
for (auto &mov: vec){
if (mov.getName() == name){
std::cout << name << std::endl;
mov.set_watched(watched + 1);
}
}
}
int main() {
std::vector<Movie> vec;
int watched = 3;
Movie p1 {"Star Wars", "PG", 2};
Movie p2 {"Indiana Jones", "PG", 1};
Movie p3 {"Matrix", "PG-13", 5};
vec.push_back(p2);
vec.push_back(p3);
std::cout << p1.getName() << std::endl;
std::cout << p1.getRatting() << std::endl;
p1.set_watched(100);
vec.push_back(p1);
std::cout << p1.getWatched() << std::endl;
display(vec);
increment_watched(vec, "Star Wars", watched);
display(vec);
return 0;
}
I want to print the vector dicVec in order to check if everything is as I want. But I can´t. I already looked it up, but nothing helped.
This is my current code:
void Translate::read(){
int i = 0;
std::ifstream dic("ende.dic");
if (dic.is_open())
{
std::string dicLine;
while (std::getline(dic, dicLine)){
std::vector<std::pair<std::string, std::string>> dicVec;
std::pair<std::string, std::string> dicPair;
std::size_t pos = dicLine.find(";");
dicPair.first = dicLine.substr(0, pos);
//std::cout << dicPair.first << " : ";
dicPair.second= dicLine.substr(pos+1);
//std::cout << dicPair.second << std::endl;
std::cout << dicVec[i];
i++;
}
}
else {
throw std::runtime_error("File could not be opened");
}
}
I also tried to print it using this:
std::cout << dicVec.at(i);
and this:
for (auto i = dicVec.begin(); i != dicVec.end(); ++i)
std::cout << *i << ' ';
But there´s always this error:
no match for operator<<
What do I have to do in order to print my vector?
Thank you for your help.
You are trying to print out a std::pair, but there is no standard operator<< implemented for std::pair, so you will have to write you own.
Even if you fix that, your code will still fail, because dicVec is empty when you call std::cout << dicVec[i]; You are not adding dicPair to dicVec before printing the contents of dicVec. In fact, dicVec should be declared above the loop, not inside of it.
Try something more like this:
typedef std::pair<std::string, std::string> stringPair;
typedef std::vector<stringPair> stringPairVec;
std::ostream& operator<<(std::ostream &out, const stringPair &p) {
out << p.first << " : " << p.second << "\n";
return out;
}
std:ostream& operator<<(std::ostream &out, const stringPairVec &vec) {
for (size_t i = 0; i < vec.size(); ++i) {
out << vec[i];
}
return out;
}
void Translate::read(){
std::ifstream dic("ende.dic");
if (!dic.is_open()) {
throw std::runtime_error("File could not be opened");
}
stringPairVec dicVec;
std::string dicLine;
while (std::getline(dic, dicLine)) {
std::size_t pos = dicLine.find(";");
stringPair dicPair = std::make_pair(
dicLine.substr(0, pos),
dicLine.substr(pos+1)
);
dicVec.push_back(dicPair);
}
std::cout << dicVec;
}
Or, in C++11 and later, you can do this instead:
using stringPair = std::pair<std::string, std::string>;
using stringPairVec = std::vector<stringPair>;
std::ostream& operator<<(std::ostream &out, const stringPair &p) {
out << p.first << " : " << p.second << "\n";
return out;
}
std:ostream& operator<<(std::ostream &out, const stringPairVec &vec) {
for (const auto &p : vec) {
out << p;
}
return out;
}
void Translate::read(){
std::ifstream dic("ende.dic");
if (!dic.is_open()) {
throw std::runtime_error("File could not be opened");
}
stringPairVec dicVec;
std::string dicLine;
while (std::getline(dic, dicLine)) {
std::size_t pos = dicLine.find(";");
dicVec.emplace_back(
dicLine.substr(0, pos),
dicLine.substr(pos+1)
);
}
std::cout << dicVec;
}
I am having an issue with my C++ program. Right now I am just trying to create a generic "variable" utilizing operator overloading. So the issues is when I determine
the type of data passed. (I must do this because I am later overloading the << operator so that ostream can output the correct data) The conditional statement
does not work as expected. Here is the code
#include <iostream>
#include <vector>
#include <istream>
#include <ostream>
class SLVar
{
public:
friend std::ostream& operator<<(std::ostream& os, const SLVar& var);
const char* str;
char ch;
int in;
float fl;
double dl;
const char* type; //Later initialized
template <typename T>
T operator=(T var)
{
if (typeid(T).name() == typeid(int).name())
{
type = "int"; in = var;
}
else if (typeid(T).name() == typeid(const char*).name())
{
type = "string"; str = var;
}
else if (typeid(T).name() == typeid(float).name())
{
type = "float"; fl = var;
}
else if (typeid(T).name() == typeid(double).name())
{
type = "double"; fl = var;
}
else if (typeid(T).name() == typeid(char).name())
{
type = "char"; ch = var;
}
}
};
std::ostream& operator<<(std::ostream& os, SLVar& var)
{
if (var.type == "string")
{
os << var.str;
}
else if (var.type == "int")
{
os << var.in;
}
else if (var.type == "float")
{
os << var.fl;
}
else if (var.type == "double")
{
os << var.dl
}
else if (var.type == "char")
{
os << var.ch;
}
return os;
}
int main()
{
SLVar var;
var = 5;
std::cout << var << std::endl;
return 0;
}
That should be the final code once that class is done. But the error persists when I try to set var = blah. It gives cannot convert const char* to int or
cannot convert char to int or anything of the sort. It was my impression that that code does not matter at all if it is not true. If I comment out the part
where I set the correct variables it runs with no issue
#include <iostream>
#include <vector>
#include <istream>
#include <ostream>
class SLVar
{
public:
friend std::ostream& operator<<(std::ostream& os, const SLVar& var);
const char* str;
char ch;
int in;
float fl;
double dl;
const char* type; //Later initialized
template <typename T>
T operator=(T var)
{
if (typeid(T).name() == typeid(int).name())
{
type = "int"; //in = var;
}
else if (typeid(T).name() == typeid(const char*).name())
{
type = "string"; //str = var;
}
else if (typeid(T).name() == typeid(float).name())
{
type = "float"; //fl = var;
}
else if (typeid(T).name() == typeid(double).name())
{
type = "double"; //fl = var;
}
else if (typeid(T).name() == typeid(char).name())
{
type = "char"; //ch = var;
}
}
};
std::ostream& operator<<(std::ostream& os, SLVar& var)
{
if (var.type == "string")
{
os << var.str;
}
else if (var.type == "int")
{
os << var.in;
}
else if (var.type == "float")
{
os << var.fl;
}
else if (var.type == "double")
{
os << var.dl;
}
else if (var.type == "char")
{
os << var.ch;
}
return os;
}
int main()
{
SLVar var;
var = "Hello world";
std::cout << var << std::endl;
return 0;
}
This runs, but only when I comment var = blah as shown above. So how can I fix this? Again it was my understanding that if the if statement is not true
the code inside wont even run. But it seem to anyway. I do not understand why this is happening. Can someone shed some light on it? Basically all I want to
do is create a "generic data type" and use the operator=() to set it.
I understand the need is to be able to declare:
SLVar var;
and later decide to assign integer, string, float, whatever without the need of fixing the type by a template (kind of dynamic typing)
I'm proposing a solution with a lot of compromises, without typeinfo at all and without templates (the template is useless here since you have to perform a type check within the function)
either, I kept only const char * and int types for simplicity's sake but that can be easily extended.
When assigning, the type is set in an enumerate, later used by the console write function.
#include <iostream>
#include <vector>
#include <istream>
#include <ostream>
class SLVar
{
private:
const char* str;
int in;
enum TheType { TYPE_INT, TYPE_CHARPTR, TYPE_UNKNOWN };
TheType type;
public:
SLVar() : type(TYPE_UNKNOWN)
{}
friend std::ostream& operator<<(std::ostream& os, const SLVar& var);
SLVar & operator=(int var)
{
in = var;
type=TYPE_INT;
return *this;
}
SLVar &operator=(const char *var)
{
str = var;
type=TYPE_CHARPTR;
return *this;
}
};
std::ostream& operator<<(std::ostream& os, const SLVar& var)
{
switch (var.type)
{
case SLVar::TYPE_CHARPTR:
return os << var.str;
case SLVar::TYPE_INT:
return os << var.in;
default:
return os; // not printing anything
}
}
int main()
{
SLVar var;
var = "Hello world";
std::cout << var << std::endl;
var = 35; // kind of dynamic typing through assignment
SLVar var2;
var2 = 56;
std::cout << var << " " << var2 << std::endl;
}
result:
Hello world
35 56
It's still missing a lot of things, like default constructor, copy constructor... but the principle works.
Try something along the lines of:
#include <iostream>
#include <vector>
#include <istream>
#include <ostream>
template <typename T>
class SLVar {
public:
SLVar<T>() {} ; // Defualt constructor
SLVar<T>(T value) :
var(value)
{} ;
T var ;
T getvalue() {return var ;}
// This lets you use the class as though it was the object
inline operator T() {return var;}
T operator=(T newvar)
{
var = newvar ;
}
};
int main()
{
SLVar<double> var_dbl(3.14);
SLVar<int> var_int(5) ;
SLVar<const char*> var_str("hello") ;
SLVar<char> var_char('y') ;
// And now to test...
std::cout << "Dbl: " << var_dbl << std::endl;
std::cout << "Int: " << var_int << std::endl;
std::cout << "Str: " << var_str << std::endl;
std::cout << "Char: " << var_char << std::endl;
// Lets try resetting the values
var_dbl = 4.6 ;
var_int = 7 ;
var_str = "goodbye" ;
var_char = 'n' ;
std::cout << "Dbl: " << var_dbl << std::endl;
std::cout << "Int: " << var_int << std::endl;
std::cout << "Str: " << var_str << std::endl;
std::cout << "Char: " << var_char << std::endl;
// Lets try some math on the double variable
std::cout << "Dbl * 0.5: " << var_dbl*0.5 << " (this shoudl be 2.3)" << std::endl;
return 0;
}
The downside is that (I'm I'm sure you've realized) the streamer wont work if you try to do SLVar<std::string>. There you just need to use SLVar<const char*>. I've also added the line:
inline operator T() {return var;}
So that the the class can act as an object of the type it is suppose to represent. So you can use the SLVar<double> as a double in a formula, for example.
I want to do is basically writing a function which takes a parameter as a file name and if have multiple files, it will just take file name as a parameter and it should do this repetitively with a function. How can i do this?
Thanks.
Txt files are like this
for example, sorular.txt:
//What is the most crowded country in the world?
//China
//USA
//Germany
//Australia
//China
int main (){
string array [5];
string line;
string answer;
static int trueCount = 0;
static int falseCount = 0;
ifstream file("/Users/User/QuizMaker/Quiz Maker V2/sorular.txt");
if(file.is_open()){
cout << "Questions are loading... Please wait.."<<endl<<" ."<<endl<<" ."<<endl<<" ."<<endl;
while (!file.eof()) {
for (int i = 0; i<6; i++) {
getline(file,array[i]);
}
for (int a = 0; a<5; a++) {
cout << array[a] << endl;
}
cin >> answer;
if(answer == "C" || answer == "c") {
cout << true;
trueCount++;
}
else falseCount++;
}
cout << "You answered "<<trueCount << " questions as true" << endl;
cout << "You answered "<<falseCount << " questions as false" << endl;
file.close();
} else cout << " not ıoen";
cin.get();
return 0;
}
First let me say, that array cannot hold elements 0, 1, 2, 3, 4, and 5. It has only allocated 5 elements.
This may stretch your horizons a bit, but I think the right solution is a class here. So i'm going to hack this together, if you're interested you can research what I've done a bit and if you don't understand something feel free to ask in a comment.
class foo : public iterator<input_iterator_tag, string> {
const initializer_list<const char*> _files;
decltype(_files)::const_iterator _filesIt;
ifstream _file;
string _line;
void get() {
string array[6];
auto i = begin(array);
while (i != end(array) && getline(_file, *i)) {
advance(i, 1);
}
if (i == end(array)) {
_line = accumulate(cbegin(array), cend(array), string(), [](const auto& a, const auto& b) { return a.empty() ? b : a + '\n' + b; });
} else if(++_filesIt != cend(_files)) {
_file.close();
_file.open(*_filesIt);
get();
}
}
public:
foo() : _filesIt(cend(_files)) {}
foo(foo& rhs) : _files(rhs._files), _filesIt(next(cbegin(_files), distance(cbegin(rhs._files), rhs._filesIt))), _line(rhs._line) {
if (_filesIt != cend(_files)) {
_file.open(*_filesIt);
_file.seekg(rhs._file.tellg());
}
}
foo(const initializer_list<const char*>&& files) : _files(files), _filesIt(cbegin(_files)), _file(*_filesIt) { get(); }
const string& operator*() const { return _line; }
const foo& operator++() {
get();
return *this;
}
const foo operator++(int) {
foo result;
get();
return result;
}
bool operator==(const foo& rhs) { return distance(_filesIt, cend(_files)) == distance(rhs._filesIt, cend(rhs._files)); }
bool operator!=(const foo& rhs) { return distance(_filesIt, cend(_files)) != distance(rhs._filesIt, cend(rhs._files)); }
};
Though this class may seem overwhelming it greatly simplifies the rest of what you're trying to acompilsh. With this class the rest of your code will read:
auto true_count = 0;
auto false_count = 0;
for_each(foo({"/Users/User/QuizMaker/Quiz Maker V2/sorular.txt", "foo.txt", "bar.txt"}), foo(), [&](const auto& i) {
string answer;
cout << i << endl;
cin >> answer;
if(answer == "C" || answer == "c") {
cout << 1;
true_count++;
} else {
false_count++;
}
});
cout << "You answered "<< trueCount << " questions as true" << endl << "You answered " << falseCount << " questions as false" << endl;
Hi guys in my previous question, I was able to get the data of a struct to be loaded on a file, but now the issue is I'm getting garbage value while retrieving it.
File Contents: settings.bin
110#NormalCompression Level210#NormalCompression Level310#NormalCompression Level410#NormalCompression Level510#NormalCompression Level
Code
#include<cstdlib>
#include<iostream>
#include<string>
#include<iomanip>
#include<fstream.h>
using namespace std;
const char* ErrorLogFilePath = "resources\\error.txt";
const char* SettingsFilePath = "resources\\settings.bin";
const int NoOfSettings = 5;
struct Setting {
int SettingID;
int SettingINTValue;
double SettingDOUBLEValue;
char SettingCHARValue;
string SettingSTRINGValue;
string SettingName;
};
istream& operator>>(istream& _is, Setting& _s) {
_is>>_s.SettingID;
_is>>_s.SettingINTValue;
_is>>_s.SettingDOUBLEValue;
_is>>_s.SettingCHARValue;
_is>>_s.SettingSTRINGValue;
_is>>_s.SettingName;
}
ostream& operator<<(ostream& _os, const Setting& _s) {
_os<<_s.SettingID;
_os<<_s.SettingINTValue;
_os<<_s.SettingDOUBLEValue;
_os<<_s.SettingCHARValue;
_os<<_s.SettingSTRINGValue;
_os<<_s.SettingName;
}
class ErrorReport {
public:
fstream ErrorFile;
void PostError(string Title,string Data,int ErrorID) {
ErrorFile.open(ErrorLogFilePath,ios::out);
ErrorFile.close();
}
} Error;
class SettingsClass {
public:
Setting setting[NoOfSettings];
void ResetSettings() {
fstream SettingFile;
Setting defaultsetting[NoOfSettings];
for(int i=1; i<=NoOfSettings; i++) {
defaultsetting[i-1].SettingID = i;
defaultsetting[i-1].SettingINTValue = 0;
defaultsetting[i-1].SettingDOUBLEValue = 0;
defaultsetting[i-1].SettingCHARValue = '#';
defaultsetting[i-1].SettingSTRINGValue = "null";
switch(i) {
default:
defaultsetting[i-1].SettingName = "Compression Level";
defaultsetting[i-1].SettingSTRINGValue = "Normal";
defaultsetting[i-1].SettingINTValue = 1;
break;
}
}
SettingFile.open(SettingsFilePath,ios::binary|ios::out);
if(SettingFile.is_open()) {
for(size_t i=0; i<NoOfSettings; ++i) {
SettingFile<<defaultsetting[i];
}
} else {
cout<<"Error!";
}
SettingFile.close();
}
void _SettingsClass() {
fstream SettingFile;
SettingFile.open(SettingsFilePath,ios::binary|ios::in);
Setting TempSettings[NoOfSettings];
if(SettingFile.is_open()) {
for(size_t i=0; i<NoOfSettings; ++i) {
SettingFile>>TempSettings[i];
}
} else {
cout<<"Error...";
}
SettingFile.close();
for(int i=0; i<NoOfSettings; i++) {
cout<<TempSettings[i].SettingINTValue<<"\n";
}
}
} Settings;
int main(int argc, char *argv[])
{
Settings._SettingsClass();
// cout<<Settings.GetSetting(1).SettingName;
system("PAUSE");
return EXIT_SUCCESS;
}
Output
4473076
1
3
0
2686384
Now Why I'm getting those garbage values? Can anyone help me, cause I think it should not turn up like this(?). And I should be getting 1 for each such element of that struct array.
Thanks in Advance!
Formatted input requires delimiters so it knows when to stop reading for a particular value. Even though you're opening the file in binary mode what you're writing is in essence a text file with no delimiters so you can't read it back.
If you must have a binary file then this is the way to read/write one using your structure:
#include <iostream>
#include <string>
#include <iomanip>
#include <fstream>
#include <vector>
const char* SettingsFilePath = "settings.bin";
struct Setting
{
int SettingID;
int SettingINTValue;
double SettingDOUBLEValue;
char SettingCHARValue;
std::string SettingSTRINGValue;
std::string SettingName;
Setting()
: SettingID(0)
, SettingINTValue(0)
, SettingDOUBLEValue(0)
, SettingCHARValue(0)
{
}
void Write(std::fstream& out)
{
out.write(reinterpret_cast<const char*>(&SettingID), sizeof(SettingID));
out.write(reinterpret_cast<const char*>(&SettingINTValue), sizeof(SettingINTValue));
out.write(reinterpret_cast<const char*>(&SettingDOUBLEValue), sizeof(SettingDOUBLEValue));
out.write(reinterpret_cast<const char*>(&SettingCHARValue), sizeof(SettingCHARValue));
size_t str_size = SettingSTRINGValue.size();
out.write(reinterpret_cast<const char*>(&str_size), sizeof(str_size));
out.write(SettingSTRINGValue.c_str(), SettingSTRINGValue.size());
str_size = SettingName.size();
out.write(reinterpret_cast<const char*>(&str_size), sizeof(str_size));
out.write(SettingName.c_str(), SettingName.size());
}
void Read(std::fstream& in)
{
in.read(reinterpret_cast<char*>(&SettingID), sizeof(SettingID));
in.read(reinterpret_cast<char*>(&SettingINTValue), sizeof(SettingINTValue));
in.read(reinterpret_cast<char*>(&SettingDOUBLEValue), sizeof(SettingDOUBLEValue));
in.read(reinterpret_cast<char*>(&SettingCHARValue), sizeof(SettingCHARValue));
size_t str_size;
std::vector<char> str_data;
in.read(reinterpret_cast<char*>(&str_size), sizeof(str_size));
str_data.resize(str_size);
in.read(&str_data[0], str_size);
SettingSTRINGValue.assign(str_data.begin(), str_data.end());
in.read(reinterpret_cast<char*>(&str_size), sizeof(str_size));
str_data.resize(str_size);
in.read(&str_data[0], str_size);
SettingName.assign(str_data.begin(), str_data.end());
}
void Print(const std::string& title)
{
std::cout << title << "\n";
std::cout << std::string(title.size(), '-') << "\n";
const size_t w = 22;
std::cout << std::setw(w) << std::right << "SettingID : " << SettingID << "\n";
std::cout << std::setw(w) << std::right << "SettingINTValue : " << SettingINTValue << "\n";
std::cout << std::setw(w) << std::right << "SettingDOUBLEValue : " << SettingDOUBLEValue << "\n";
std::cout << std::setw(w) << std::right << "SettingCHARValue : " << SettingCHARValue << "\n";
std::cout << std::setw(w) << std::right << "SettingSTRINGValue : " << SettingSTRINGValue << "\n";
std::cout << std::setw(w) << std::right << "SettingName : " << SettingName << "\n";
std::cout << "\n";
}
};
int main()
{
{
Setting s;
s.Print("Default before Write");
s.SettingID = 1;
s.SettingINTValue = 2;
s.SettingDOUBLEValue = 3.5;
s.SettingCHARValue = 'Z';
s.SettingSTRINGValue = "Blah Blah";
s.SettingName = "Some Settings";
std::fstream f(SettingsFilePath, std::ios::out | std::ios::binary);
s.Write(f);
s.Print("Values written to file");
}
{
Setting s;
s.Print("Default before read");
std::fstream f(SettingsFilePath, std::ios::in | std::ios::binary);
s.Read(f);
s.Print("Values after read");
}
return EXIT_SUCCESS;
}
It seems you forgot to load your setting into file.
int main(int argc, char *argv[])
{
Settings.ResetSettings(); // insert code here
Settings._SettingsClass();
// cout<<Settings.GetSetting(1).SettingName;
system("PAUSE");
return EXIT_SUCCESS;
}