Save/Load workspace in C++ application - c++

I'm working on adding a new feature to an existing program. It's basically a save/load workspace feature, where a user can save the positions of their windows, and then load said positions whenever they want to by selecting a menu item. In order to implement this, I have created code which extracts the screen coordinates of the window and writes them to a file (below) :
void CMainFrame::SaveWorkspace()
{
RECT ctrlsize;
m_pDialog->GetWindowRect((LPRECT)&ctrlsize); //obtains location for window
ofstream Workspace("saveone", ios::out);
Workspace << ctrlsize.left << "," << ctrlsize.top << "," << ctrlsize.right << "," << ctrlsize.bottom;
}
And this (is supposed to) loads the workspace:
void CMainFrame::LoadWorkspace()
{
//Read in the data from the file
int data[3][4];
int r=0;
int a=0;
int b=0;
ifstream infile;
infile.open("saveone");
for(a = 0; a< 3; a++)
{
for(b = 0;b<4;b++)
{
infile >> data[a][b];
cout << data[a][b];
}
}
infile.close();
//Now, assign the extracted values
RECT ctrlset;
ctrlset.top = data[0][1];
ctrlset.left = data[0][0];
ctrlset.right = data[2][0];
ctrlset.bottom = data[0][3];
// Finally, reassign the window positions
m_pDialog->SetWindowPos(NULL, ctrlset.left, ctrlset.top, (ctrlset.right - ctrlset.left), (ctrlset.bottom - ctrlset.top), SWP_SHOWWINDOW);
}
Problems:
1) the SaveWorkspace function works sporadically; more often than not, it doesn't create a file.
2) the LoadWorkspace function doesn't work. Specifically, only the data[0][0] coordinate gets saved to the array (the first value in the file).
This seems like a fairly easy thing to do, I'm a bit embarrassed that it's giving me so much trouble...
EDIT: I've fixed problem #1. Now I just need to figure out why my array isn't working.

You have at least two problems in the reading.
Your array definition is wrong. It is :
data[2][3];
This has only 6 values.
However, in the loop you are reading 12 values out.
You have the "," values in the file. You are not getting rid of them.
Maybe as an easy solution, you could add a new line after each entry when you write them.
Or you could enter the details of a single rectangle on one line, then read the full line and parse for the individual components yourself.

Related

Bug writing into Excel file - C++

When I send a variable into Excel it changes its value. It just happens with excel. It also just happens when the variable is stored in a container. I guess it is more clear if you see the code:
#include<iostream>
#include<array>
#include<vector>
#include<fstream>
const int aSize{ 150000 };
std::array<double, aSize> anArray{};
int main(void)
{
double aValue{ 0.00000005467 };
std::vector<double> aVector;
for (int i = 0; i < aSize; ++i)
{
anArray[i] = aValue;
aVector.push_back(aValue);
}
std::ofstream fileOne, fileTwo, fileThree, fileFour, fileFive;
fileOne.open("array.xls");
fileTwo.open("array.txt");
fileThree.open("vector.xls");
fileFour.open("vector.txt");
fileFive.open("value.xls");
fileOne << anArray[0];
fileTwo << anArray[0];
fileThree << aVector[0];
fileFour << aVector[0];
fileFive << aValue;
std::cout << aValue << "\n" << anArray[0] << "\n" << aVector[0];
return 0;
}
All I do is populate a vector and an array. If I print the value of the variable I get the expected value. If I send it into a .txt I get the expected value. If I send just the value into Excel I get the expected value.
It all just breakes down when I send the value from the containers into Excel. Why can this be happening?
What seems likely to be the problem here is the way the Excel is interpreting the (formatted) numerical output from your c++ program. Even though the text may be correct (from the point of view of the cout function) it may not have the 'correct' decimal point character in it (i.e. a dot instead of a comma, or vice versa).
Solution: Make sure that Excel is set to use the same "locale" as the default c++ locale, or set the c++ locale to whatever Excel is using.
The MS-XLS file format is not a simple text file. You cannot simply put text into it and expect it to show up correctly. You would need more code and/or specialized libraries to interact with it.
See the suggestions here.

C++ the first cout will not be printed

As you can see, I have a cout here before the loop starts. Seekg starts at the beginning and the first word in the txtfile is "Hello". But it doesn't print it out(the first cout).
When I remove the while loop, then its not a problem, the first word gets included in the output.
The first "cout", shouldn't it be printed out no matter what comes after it? How is it possible that next lines of code(THIS case) affects the previous "cout" above it ?
int main()
{
string a;
ifstream myfile;
myfile.open("test.txt");
myfile.seekg(0);
getline(myfile,a);
cout << a << endl;
int z = 0;
while( a != "x" ) {
myfile.seekg(z);
getline(myfile,a);
z += a.size() + 2;
cout << a << endl;
}
}
I Also should mention that the file starts with "hello", AND contains 600 newlines and a word on every new line. The last line contains "x".
[EDIT]
Here's another example. I belive this will be helpful. This is my code now:
int main() {
string a;
ifstream myfile;
int newpos = 0;
myfile.open("example.txt");
myfile.seekg(newpos);
getline(myfile,a);
while (a != "x") {
myfile.seekg(newpos);
getline(myfile,a);
cout << a << endl;
newpos += a.size() + 2;
}
}
This is my textfile:
hello
johan
nils
erik
john
x
The output is exactly as it looks in the textfile above.(so far so good).
BUT, then I add about 600 new names to the list/textfile(same structure as above, no changes there, just new names added). Only ONE "hello" at the top so I can track the start, and one x at the end.
This still works with around 100 new names, hello is still printed out in the beginning. But when i add around 600 new names , hello will not be included(the very first cout). Why is that?
But when I add around 600 new names, hello will not be included (the very first cout).Why is that?
Looks like your Screen Buffer Size wasn't big enough to show all of the buffer lines. So when the number of printed lines exceeds a specific height, the console starts to ignore the previously printed lines which result you think it didn't print them all.
Since you're using Windows you can try to increase it as so
For all console apps
Right-click the title of the console and choose Defaults
go to Layout tab
Under the Screen Buffer Size, Increase the Height to (i.e 9001)
Click OK then restart the console
For a specific app
Right-click the title of the console and choose Properties
go to Layout tab
Under the Screen Buffer Size, Increase the Height to (i.e 9001)
Click OK.
Note that the Default Height in most Windows Operating systems is 9001.

Save the variables of an object to then be able to initialise another object with those variables

What I am trying to achieve is this:
Let's say I have a class Score. This class has an int variable and a char* variable.
Now when I have an object Score score, I would like to be able to save the value of those variables (I guess to a file). So now this file has an int variable and a char* variable that I can then access later to create a new Score object.
So I create Score score(10, "Bert");. I either do something like score.SaveScore(); or the score gets saved when the game is over or the program exits, it doesn't matter.
Basically I am looking for the equivalent/correct way of doing this:
score.SaveScore(FILE file)
{
file.var1 = score.score;
file.var2 = score.name;
}
I realize this is probably very stupid and not done this way whatsoever! This is just me trying to explain what I am trying to achieve in the simplest way possible.
Anyway, when I run the program again, that original Score score(10, "Bert") does not exist any more. But I would like to be able to access the saved score(from file or wherever it may be) and create another Score object.
So it may look something like:
LoadScore(FILE file)
{
Score newScore(file.var1, file.var2);
}
Again, just trying to show what I am trying to achieve.
The reason why I want to be able to access the variables again is to eventually have a Scoreboard, the Scoreboard would load a bunch of scores from the file.
Then when a new score is created, it is added to the scoreboard, compared to the other scores currently in the scoreboard and inserted in the right position (like a score of 6 would go in between 9 and 4).
I feel like this was a bit long winded but I was trying to really explain myself well! Which I hope I did!
Anyway, I am not looking for someone to tell me how to do all of that.
All I am after is how to do the initial save to a file.
Thank you for any suggestions.
I would use the <fstream> library, like this;
//example values
int x=10;
float y=10.5;
const char* chars = "some random value";
string str(chars); //make string buffer for sizing
str.resize(20); //make sure its fixed size
//open a test.txt file, in the same dir for output
std::ofstream os("test.txt", std::ios::out | std::ios::binary); //make it output binary
//(char*) cast &x, sizeof(type) for values/write to file chars for x and y
os.write((char*)&x, sizeof(int)); //only sizeof(int) starting at &x
os.write((char*)&y, sizeof(float)); //cast as a char pointer
os.write(str.data(), sizeof(char)*str.size()); //write str data
os.close();
//the file test.txt will now have binary data in it
//to read it back in, just ifstream, and put that info in new containers, like this;
int in_x = 0; //new containters set to 0 for debug
float in_y = 0;
char inchar[20]; //buffer to write 20 chars to
ifstream is("test.txt", std::ios::in | std::ios::binary); //read in binary
is.read((char*)&in_x, sizeof(int)); //write to new containers
is.read((char*)&in_y, sizeof(float));
is.read((char*)&inchar, sizeof(char)*20); //write char assuming 20 size
is.close();
//outputting will show the values are correctly read into the new containers
cout << in_x << endl;
cout << in_y << endl;
cout << inchar << endl;
I realize this is probably very stupid and not done this way whatsoever!
The entire software industry was stupid enough to have it done so many times that even a special term was invented for this operation - serialization and nearly all C++ frameworks and libraries have implemented this in a various ways.
Since question is tagged with C++ I would suggest you to look at boost serialization but there are many other implementations.
Do you need that file to be readable by a human? If yes than consider, for example, XML or JSON formats.
You don't need it be readable but want it be as compact as possible? Consider google protobuf
Just start doing it and come with a more specific question(s).
As it was mentioned before, keep strings as std:string objects rather then char*
About writing/reading to/from files in C++ read about fstream

Write output to new files at every nth iteration

A fragment of my code is :
for (int iter = 0; iter < flags.total_iterations_; ++iter) {
if (iter%20==0) {
std::ofstream mf(flags.model_file_.c_str());
accum_model.AppendAsString(word_index_map, mf); }
else {
std::cout << "Model not created for "; }
std::cout << "Iteration " << iter << " ...\n";
So, I am trying to generate outputs from method accum_model at every 20th iteration. But, the problem is I have to write the output in new file everytime the 20th iteration is reached. Now, my output is being overwritten.
I execute this code with the help of a executible, which is as:
./lda --num_topics 15 --alpha 0.1 --beta 0.01 --training_data_file testdata/test_data.txt --model_file MF/lda_model.txt --burn_in_iterations 120 --total_iterations 150
The MF/lda_model.txt is the output file given. I am not understanding how to link the file that contains the code and this executible command as I would need 5 different new files (for 100 iterations - as data is written into a new file every 20th iteration).
I am new to coding and so far, I was coding in python. I tried till this loop, I am confused about how to create new files and get corresponding outputs. Please help! Thanks in advance.
Use std::stringstream, and build a new file name to open each time.
std::string uniquePathFileNamePostFix (int i) {
std::stringstream ss;
ss << '-' << i ;
return (ss.str());
}
The idea is to use the stringstream to create (or append or prepend) a unique modifier based on i. (or anything else convenient - I have used time stamps).
If I understand your question correctly, you are overwriting the ofstream instead of appending to it.
You'll want to specify the 'app' flag in the mode of the ofstream constructor:
std::ofstream mf(flags.model_file_.c_str(), std::ios_base::app);
If you need to start the output with an new, "empty" file, just leave out the mode (ofstream defaults to std::ios_base:out, whether you specify it or not): std::ofstream::ofstream
...and if you need a new output file (according to your OP), you need to change the file name in flags.model_file_.
I'm not sure that I understand your question correctly, but I think you want to output every 20th iteration in a new file. To do so, you just need to append the value of theiter to the name of the file or otherwise add a "dynamic" element to it.
The way to do it using only standard C++ is using stringstream:
std::stringstream file_name;
file_name << flags.model_file_ << iter;
result = file_name.str();

Logic for reading rows and columns from a text file (textparser) C++

I'm really stuck with this problem I'm having for reading rows and columns from a text file. We're using text files that our prof gave us. I have the functionality running so when the user in puts "numrows (file)" the number of rows in that file prints out.
However, every time I enter the text files, it's giving me 19 for both. The first text file only has 4 rows and the other one has 7. I know my logic is wrong, but I have no idea how to fix it.
Here's what I have for the numrows function:
int numrows(string line) {
ifstream ifs;
int i;
int row = 0;
int array [10] = {0};
while (ifs.good()) {
while (getline(ifs, line)) {
istringstream stream(line);
row = 0;
while(stream >>i) {
array[row] = i;
row++;
}
}
}
}
and here's the numcols:
int numcols(string line) {
int col = 0;
int i;
int arrayA[10] = {0};
ifstream ifs;
while (ifs.good()) {
istringstream streamA(line);
col = 0;
while (streamA >>i){
arrayA[col] = i;
col++;
}
}
}
edit: #chris yes, I wasn't sure what value to return as well. Here's my main:
int main() {
string fname, line;
ifstream ifs;
cout << "---- Enter a file name : ";
while (getline(cin, fname)) { // Ctrl-Z/D to quit!
// tries to open the file whose name is in string fname
ifs.open(fname.c_str());
if(fname.substr(0,8)=="numrows ") {
line.clear();
for (int i = 8; i<fname.length(); i++) {
line = line+fname[i];
}
cout << numrows (line) << endl;
ifs.close();
}
}
return 0;
}
This problem can be more easily solved by opening the text file as an ifstream, and then using std::get to process your input.
You can try for comparison against '\n' as the end of line character, and implement a pair of counters, one for columns on a line, the other for lines.
If you have variable length columns, you might want to store the values of (numColumns in a line) in a std::vector<int>, using myVector.push_back(numColumns) or similar.
Both links are to the cplusplus.com/reference section, which can provide a large amount of information about C++ and the STL.
Edited-in overview of possible workflow
You want one program, which will take a filename, and an 'operation', in this case "numrows" or "numcols". As such, your first steps are to find out the filename, and operation.
Your current implementation of this (in your question, after editing) won't work. Using cin should however be fine. Place this earlier in your main(), before opening a file.
Use substr like you have, or alternatively, search for a space character. Assume that the input after this is your filename, and the input in the first section is your operation. Store these values.
After this, try to open your file. If the file opens successfully, continue. If it won't open, then complain to the user for a bad input, and go back to the beginning, and ask again.
Once you have your file successfully open, check which type of calculation you want to run. Counting a number of rows is fairly easy - you can go through the file one character at a time, and count the number that are equal to '\n', the line-end character. Some files might use carriage-returns, line-feeds, etc - these have different characters, but are both a) unlikely to be what you have and b) easily looked up!
A number of columns is more complicated, because your rows might not all have the same number of columns. If your input is 1 25 21 abs 3k, do you want the value to be 5? If so, you can count the number of space characters on the line and add one. If instead, you want a value of 14 (each character and each space), then just count the characters based on the number of times you call get() before reaching a '\n' character. The use of a vector as explained below to store these values might be of interest.
Having calculated these two values (or value and set of values), you can output based on the value of your 'operation' variable. For example,
if (storedOperationName == "numcols") {
cout<< "The number of values in each column is " << numColsVal << endl;
}
If you have a vector of column values, you could output all of them, using
for (int pos = 0; pos < numColsVal.size(); pos++) {
cout<< numColsVal[pos] << " ";
}
Following all of this, you can return a value from your main() of 0, or you can just end the program (C++ now considers no return value from main to a be a return of 0), or you can ask for another filename, and repeat until some other method is used to end the program.
Further details
std::get() with no arguments will return the next character of an ifstream, using the example code format
std::ifstream myFileStream;
myFileStream.open("myFileName.txt");
nextCharacter = myFileStream.get(); // You should, before this, implement a loop.
// A possible loop condition might include something like `while myFileStream.good()`
// See the linked page on std::get()
if (nextCharacter == '\n')
{ // You have a line break here }
You could use this type of structure, along with a pair of counters as described earlier, to count the number of characters on a line, and the number of lines before the EOF (end of file).
If you want to store the number of characters on a line, for each line, you could use
std::vector<int> charPerLine;
int numberOfCharactersOnThisLine = 0;
while (...)
{
numberOfCharactersOnThisLine = 0
// Other parts of the loop here, including a numberOfCharactersOnThisLine++; statement
if (endOfLineCondition)
{
charPerLine.push_back(numberOfCharactersOnThisLine); // This stores the value in the vector
}
}
You should #include <vector> and either specific std:: before, or use a using namespace std; statement near the top. People will advise against using namespaces like this, but it can be convenient (which is also a good reason to avoid it, sort of!)