Reputation: 43
Is there a way to create a console application program that asks input data (eg users birth dates, favourite food, everything) and does anything i program it to do and keep those data stored in that .exe when i close it?
This way, when I'll open it again, all those datas will still be saved there, so I just have to update or modify them.
Upvotes: 2
Views: 4062
Reputation: 1
As I explain in my other answer (which you should read before this one), you don't want to save data inside your .exe
file.
But I am guessing that you want to keep user birth date (and other data) from one run to the next. This answer focus mostly on that "users birth date" aspect and guesses that your question is some XY problem (you really care about birth dates, not about overwriting an executable).
So, you decide to keep them somewhere (but outside of your executable). That could be a textual file; perhaps using JSON or YAML format, or some other textual file format that you define properly, specified in EBNF notation in some document; or a binary file (perhaps protocol buffers as suggested by P.W, or some sqlite "database file", or your own binary format that you need to document properly). It is very important to document properly the file format you are using.
Dealing with a textual file (whose format you have well defined) is easy with just fopen. You first need to define well defined a file path, perhaps as simple as
#define MYAPP_DATA_PATH "mydata.txt"
or better
const char* myapp_data_path = "mydata.txt";
(in reality, you better use some absolute file path to be able to run your program from various working directories, and provide some way to redefine it, e.g. thru program options, i.e. command-line arguments)
You might also need to organize some data structure (a global variable MyData global_data;
perhaps) keeping that data. In C++, you'll define some class MyData;
and you want it to have at least member functions like void MyData::add_birth_date(const std::string& person, const std::chrono::time_point& birthdate);
and void MyData::remove_birth_date(const std::string& person);
. Probably you'll have more classes like class Person;
etc...
So your application starts first by filling global_data
if a file mydata.txt
exists (otherwise, your global_data
keeps its empty initial state). That is simple, you'll have some initialization function like:
void initial_fill_global_data(void) {
std::ifstream input(myapp_data_path);
// the file opening could have failed.... then we return immediately
if (!input || !input.good() || input.fail())
return;
Of course, you need to parse that input
. Use well known parsing techniques that would call global_data.add_birth_date
appropriately. Notice that for the JSON format, you'll find good C++ libraries (such as jsoncpp) to make that really easy.
Before exiting your application, you should save that file. So you would call a save_global_data
function wich outputs into the mydata.txt
file the contents of MyData
. BTW, you could even register it with std::atexit
.
The functions initial_fill_global_data
and save_global_data
could be member functions (perhaps static
ones) of your MyData
class.
You might want your program to lock the data file. so that two processes running your program won't make havoc. This is operating system specific (e.g. flock(2) on Linux).
I also suggested to keep your data in an sqlite database file. Read some sqlite tutorial and refer to sqlite C & C++ interface reference documentation. Then you need to think of a well designed database schema. And you don't need anymore to keep all the data in memory, since sqlite is capable of managing a big amount of data (many gigabytes), more that what fits in memory.
Obviously you need a global database pointer. So declare some global sqlite3*db;
. Of course, myapp_data_path
is now some "mydata.sqlite"
path. Your main
starts by opening that (and creating an empty database if necessary) using
int opsta = sqlite3_open(myapp_data_path, &db);
if (opsta != SQLITE_OK) {
std::cerr << "failed to open database " << myapp_data_path
<< " with error#" << opsta << "=" << sqlite_errstr(opsta)
<< std::endl;
exit (EXIT_FAILURE);
}
If the database did not exist, it is created empty. In that case, you need to define appropriate tables and indexes in it. My first suggestion could be something as simple as
char* errormsg = NULL;
int errcod = sqlite3_exec(db,
"CREATE TABLE IF NOT EXISTS data_table ("
" name STRING NOT NULL UNIQUE,"
" birthdate INT"
")",
&errormsg);
if (errcod != SQLITE_OK) {
std::cerr << "failed to create data_table " << errormsg << std::endl;
exit(EXIT_FAILURE);
}
Of course, you need to think of some more clever database schema (in reality you want several tables, some database normalization, and you should cleverly add indexes on your tables), and to prepare the queries (transform them into sqlite_stmt
-s) done in your program.
Obviously you should not save data inside your executable. In all my approaches above, your myapp
program behaves as you want it to be. The first time it is running, it initialize some data -outside of the myapp
executable- on the disk if that data was missing. The next times, it reuses and updates that data. But that myapp
executable is never rewritten when running.
Upvotes: 0
Reputation: 1
Is there a way to create a [...] program that asks input data [...] then keep those data stored in that .exe when i close it?
There is no simple way (but you don't need that). What you want is related to persistence and application checkpointing.
In practice, you probably want to store data in a file -not your executable- (perhaps using some textual format like JSON) or in some database (perhaps as simple as some sqlite, or interacting with some RDBMS like PostGreSQL). For things like birthdays and food preference, an sqlite
database file is probably the good approach (see some SQLite tutorial). Put efforts in the good design of your database schema.
This way, when I'll open it again, all those datas will still be saved there
Those datas will still be there if you keep them in some outside file (perhaps a simple myappdata.sqlite
one). You can easily design your program to create that file if it does not exist (this happens only the first time you run your program; on the next runs, your program would successfully read that data from that outside file at startup).
In most current operating systems (read this textbook to learn more about OSes) notably Windows, MacOSX, Linux, Android, ..., the executable is supposed to be read-only. And it might be running in several processes at the same time (in such case, what should happen? Think of ACID properties).
The usual practice is to store data outside of the executable (most programs, including your text processor, your compiler, your web browser, ... are doing that). You don't explain why you want to store some data inside the executable, and doing so is unusual and highly operating system specific and executable format specific (for Linux, study carefully elf(5)...)
I would suggest to save the data in some optional file (or database) - its filepath could have some wired-in constant default, etc.... At startup, you check the existence of that data (e.g. with access(2) on POSIX, or just by handling the failure case of fopen
or sqlite3_open
etc....). If it does not exist, you initialize your program data somehow. At exit (or save time), you write that data. BTW most programs are doing so.
Notice that on most operating systems and computers, a software is not simply a single executable file, but much more (e.g. required libraries and dependencies, configuration files, data files, build automation scripting such as Makefile
, etc...). Its installation is a well identified technical process (sometimes a quite complex one), and package managers are helpful.
My feeling is that without specific motivation, you should not even try to store (mutable) data (persistently) in your executable (it is complex, brittle since very OS & compiler and build-chain specific, unusual, and opens vulnerabilities).
For completeness, some programs did actually write some data by rewriting their executable. On Linux, GNU emacs
is doing that (in practice, only during its installation procedure) in its unexec.c
file (very brittle, since OS & compiler specific) but that feature is disputed and is likely to disappear.
Many other systems deal cleverly with orthogonal persistence: SBCL has some save-lisp-and-die
primitive (it usually persists the state in some other "image" file). Poly/ML has some export
facility. J.Pitrat's CAIA system (see this paper and his blog; a 2016 tarball of CAIA is available -with permission- on my home page) is able to regenerate entirely all its C code and all the required data (in thousands of files). FullPliant is persisting its state in a well organized file tree. Such persistence or checkpointing techniques are tied to garbage collection (so you should then read the GC handbook) and are using techniques and algorithms close to copying garbage collection.
FWIW, my current project, bismon, is orthogonally persisting its entire heap, but do that outside of the main executable (in an ideal world, I would like to re-generate all the C or C++ source code of it; I am far from that goal).
My recommendation is to keep your software in several files: its executable, the C++ source code related to it, its data files (and probably much more dependencies, i.e. shared libraries or DLLs, font and image files, required binaries, etc...). Then you don't need to overwrite your executable when persisting your state. Since you mention C++ (which is not homoiconic), you could generate the C++ code of your system (then called a Quine program) with its persistent data (and leave the recompilation of all that generated C++ to the system's C++ compiler). I also recommend to make your self-generating program some free software. (if you do that, be nice to edit your question to gives its URL).
In C++, you might keep the data inside the executable (again, it is a bad idea, and I hope to have convinced you to avoid that approach) in the following way: You add one C or C++ source file (e.g. mydata.cc
) which contains only data (e.g. some big const char data[]="... many lines of data ...";
) - BTW, the XBM file format could be inspirational. You keep all the other *.o
object files (in a place known to your program). To save data, you regenerate that mydata.cc
file (with the new data for your current state) at each save operation, and at last you run the appropriate commands (perhaps using std::system in your code) to compile that mydata.cc
and link it with the kept *.o
into a fresh executable. So every save operation requires the recompilation of data.cc
and its linking with other *.o
object files (and of course the C++ compiler and linker, perhaps with additional build automation tools, becomes a required dependency of your program). Such an approach is not simpler than keeping an external data file (and requires to keep those *.o
object files anyway).
This way, when I'll open it again, all those datas will still be saved there
If your goal is just to get the data if it was written in the past, just keep the data in some optional database or file (as many programs do: your word processor would ask you to save its document before exiting if you start it without any document and write a few words in it) outside of your executable and write it before exiting your program. No need to overwrite your executable!
Upvotes: 5
Reputation: 26800
What you want to do requires the ability to write into (and possibly read from) an executable while it is running. As far as I know this is not possible. While it is possible to change the behaviour of a running executable based on the user input which it is pre-conditioned to receive (think of a video game), it is not possible to store those inputs directly into the exe.
Video games store the progress, points of the player (which are the result of the inputs from the player) into a file(s) outside the running .exe.
So you will have to store the data in a file outside of the .exe file. I normally use google protocol buffers to do this. A good explanation of them can be found here.
They are free, simple to use and supported for C++.
They are better than other formats like XML. Some of the advantages are mentioned here
Protocol buffers have many advantages over XML for serializing structured data.
Protocol buffers:.
- are simpler
- are 3 to 10 times smaller
- are 20 to 100 times faster
- are less ambiguous
- generate data access classes that are easier to use programmatically
Upvotes: 1