C# - Save Variables of a Program - c#

I'm making a game now in C# (which is a Console Application) and its variables need to be saved.
I've tried using Settings but there's a big problem about it: If the file name is changed or the file is transferred to somewhere else, the Settings are lost.
So what is a good alternative to Settings for saving variables and retrieving them later in the application?
EDIT: I'd like to save the variables to a text file and retrieve it later, is it possible? If yes, then how?
And please don't suggest online servers, because I'm working on a singleplayer game without keeping tracks of the players whatsoever.

One simple way to store data of a fixed type is serialization with the BinaryFormatter class.
See the MSDN documentation for Binary Formatter. I've copied some of the relevant code here.
using System;
using System.IO;
using System.Collections;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Serialization;
void SaveData()
{
// Create a hashtable of values that will eventually be serialized.
Hashtable addresses = new Hashtable();
addresses.Add("Jeff", "123 Main Street, Redmond, WA 98052");
addresses.Add("Fred", "987 Pine Road, Phila., PA 19116");
addresses.Add("Mary", "PO Box 112233, Palo Alto, CA 94301");
// To serialize the hashtable and its key/value pairs,
// you must first open a stream for writing.
// In this case, use a file stream.
FileStream fs = new FileStream("DataFile.dat", FileMode.Create);
// Construct a BinaryFormatter and use it to serialize the data to the stream.
BinaryFormatter formatter = new BinaryFormatter();
try
{
formatter.Serialize(fs, addresses);
}
catch (SerializationException e)
{
Console.WriteLine("Failed to serialize. Reason: " + e.Message);
throw;
}
finally
{
fs.Close();
}
}
void LoadData()
{
// Declare the hashtable reference.
Hashtable addresses = null;
// Open the file containing the data that you want to deserialize.
FileStream fs = new FileStream("DataFile.dat", FileMode.Open);
try
{
BinaryFormatter formatter = new BinaryFormatter();
// Deserialize the hashtable from the file and
// assign the reference to the local variable.
addresses = (Hashtable) formatter.Deserialize(fs);
}
catch (SerializationException e)
{
Console.WriteLine("Failed to deserialize. Reason: " + e.Message);
throw;
}
finally
{
fs.Close();
}
// To prove that the table deserialized correctly,
// display the key/value pairs.
foreach (DictionaryEntry de in addresses)
{
Console.WriteLine("{0} lives at {1}.", de.Key, de.Value);
}
}

If your app structure is dynamic by it's nature, so it's name can be changed, location can be changed (even if , to be honest, don't understand reasons behind that) the only possibility I can see is relay in external source for retrieving or storing your config information.
In short: setup a server somewhere that holds your app configuration data, and on first startup try to reach that server, load file from it, read a data. If it fails, just load default information.
Good candidates could be : DropBox, SkyDrive, GoogleDrive, Box... find suitable C# API for any of them an store/read data you need. The only thing I would invite your attention to for this solution, is licensing. Keep an eye on it, and be sure that you can use it in your application in a way you decide to use it.

Saving the values out to a flat file...
Storing the values in an XML File, or a database file...
Windows Registry...
There are many places you can store information, and only experience will really teach you what to put where... To make an intelligent guess, you need to be familiar with all the approaches...

The only real option that isn't susceptible to the user intentionally changing the data stored on their computer, losing it due to changing machines, etc. would be to not store the data on their computer at all. Have a database or other server that you host that users connect to over the network which stores their data for them.

You may try to use the Isolated Storage
Isolated storage is not available for Windows Store apps. Instead, use
the application data classes in the Windows.Storage namespaces
included in the Windows Runtime API to store local data and files.
You may also try to use XML file to store the users setting and then store it in the SpecialFolder.ApplicationData directory.
You can also use the app.config file to save application-level settings

Related

Saving data with object-based data source in winforms app

I am building a C# winforms application which needs to read in data from multiple files and allow the user to view/edit the data. There will be a large amount of data, so the user needs to be able to save their changes, close the program, and resume their work later.
I am struggling with the best approach for retaining this data after the user exits the program. I've followed a tutorial for data binding to objects, but in this tutorial the data is hardcoded into the Form_Load event and the changes are lost when you exit the program. The author alludes to preferring to use an object-based data source instead of a database for data binding, but doesn't describe on how/if he saves data after the user exits.
Is there a way to store the data in the object-based data source between sessions, without setting up a local database or manually writing to some type of file? Or must I set up a local database in order to save data?
As users Jimi and bhmahler mentioned in the comments, the concept I was looking for was Object Serialization.
I created the following method to save my data:
private void Serialize()
{
Stream s = File.Open("data.txt", FileMode.Open);
BinaryFormatter b = new BinaryFormatter();
List<Airplane> data = new List<Airplane>();
foreach (var a in bsAirplanes) //bsAirplanes is the bindingsource object
{
data.Add((Airplane)a);
}
b.Serialize(s, data);
s.Close();
}
And this method to load saved data:
private void Deserialize()
{
Stream s = File.OpenRead("data.txt");
BinaryFormatter b = new BinaryFormatter();
List<Airplane> data = (List<Airplane>) b.Deserialize(s);
foreach(Airplane a in data)
{
bsAirplanes.Add(a);
}
s.Close();
}
I also had to mark the Airplane class with the [Serializable()] attribute.

WP8: Losing data or access to XML file in isolated storage

I am creating a WP8 shopping list app that stores user created lists(in my code, each shopping list is defined as a ListObj that I defined). I would like to save the lists created by users through an .xml file. As long as I continue to add to this list of ListObj's, I seem to have no issues. But I start to experience trouble when I want to remove a ListObj from my list. When I reopen my app after I removed something from my list of ListObj's and attempt to load my list upon start, I enter this try/catch block:
try
{
using (IsolatedStorageFile appStorage =
IsolatedStorageFile.GetUserStoreForApplication())
{
if (appStorage.FileExists("rootList.xml"))
{
using (IsolatedStorageFileStream isStream =
appStorage.OpenFile("rootList.xml",
FileMode.Open, FileAccess.Read))
{
XmlSerializer serializer = new XmlSerializer(typeof(List<ListObj>));
rootList = (List<ListObj>)serializer.Deserialize(isStream);
}
}
else
{
rootList = new List<ListObj>();
Debug.WriteLine("rootList not found.");
}
}
}
catch
{
///Uhhh....
}
However, my program executes the catch statement in which nothing happens obviously. I am unsure of what to execute in this catch block in order to diagnose my problem. I think I am losing access to the app's Isolated storage but again, I am unsure as to how to proceed. Any ideas?
So I ended up finding a solution to my problem. It turns out that the way I modified my .xml file caused an error in which it can no longer be read. I solved this by completely overwriting my file with the modified data rather than trying to change the existing data.

dont want to overwrite my ini file

I am using ini file to store my configuration in my c# gui.
but when i start my gui again , and save the configuration, the previous saved configuration gets overwritten.
IS there a way to keep on saving configurations ?
You want to use an app.config file instead of your .ini. You access the settings in it using the ConfigurationManager from the System.Configuration namespace. You can even create custom configuration sections by creating classes that inherit from ConfigurationSection. That will give you intellisense support of your config file, as well.
One example of that (it's using asp.net, but it works for any .net code) is here.
Edit: Re-reading your question, I'm unclear on if you're trying to save application settings (app.config), or if you're trying to save session data to disk (saving records or serializing objects). If the former, look at app.config. You can even have multiple items that set the same "settings" but with different values (such as having multiple SQL Connection strings) and then call them by some parameter you obtain from a user.
If you're trying to save session data/state, then you want to serialize your objects- look into serialization/deserialization (many options available there) and the System.IO namespace for persisting to disk.
The only way to prevent overwriting the same file each time is to make the file name unique e.g.
FileName<TimeStamp>.ini
Or
FileName<Guid>.ini
Or you could even do what windows does with duplicate files and check how many already exist and append a new number onto the end e.g.
FileName.ini
FileName1.ini
FileName2.ini
Personally I would go with the timestamp/GUID approach. Here's some example code
class Program
{
static void Main()
{
for (int i = 0; i <= 10; i++)
{
SaveConfiguration();
Thread.Sleep(500);
}
}
private static void SaveConfiguration()
{
string fileName = System.IO.Path.Combine(#"Config\File\Dir", String.Format("Config{0:yyyyMMddHHmmss}.ini", DateTime.UtcNow));
System.IO.File.WriteAllText(fileName, "File contents");
}
}

Small Simple Local Data Store for keeping user settings

I have this tiny C# winforms application that will NOT grow larger in any way.
It's just two input fields and a button.
I want to know if you guys have knowledge of a way to store the values that a user inputs in a local datastore. You may consider 10 records to be a lot of data for this scenario.
Requirements
It shouldn't require any setup from the database side. (table creation, etc)
I should be able to just give it an object and it should store it, I don't want to waste time on that.
The data needs to be fairly easily retrievable.
I want to be able to reuse this thing for every small app I create like this.
My Ideas
A POCO object that will be XML-Serialized and saved to the Local Settings folder. Upon loading of the app, this file is deserialized back into the POCO object.
An OODBMS: I have no experience with these but I always thought they consisted of a single dll so it would be easy to package them with the program.
I once, a long long time ago, built an application that stored user settings inside the registry. Don't know if that is still appreciated though.
What do you think is the best approach?
Code samples are very much appreciated!
I've taken both answers into account and built the following:
public static class IsolatedStorageExtensions
{
public static void SaveObject(this IsolatedStorage isoStorage, object obj, string fileName)
{
IsolatedStorageFileStream writeStream = new IsolatedStorageFileStream(fileName, FileMode.Create);
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(writeStream, obj);
writeStream.Flush();
writeStream.Close();
}
public static T LoadObject<T>(this IsolatedStorage isoStorage, string fileName)
{
IsolatedStorageFileStream readStream = new IsolatedStorageFileStream(fileName, FileMode.Open);
BinaryFormatter formatter = new BinaryFormatter();
T readData = (T)formatter.Deserialize(readStream);
readStream.Flush();
readStream.Close();
return readData;
}
}
A wrapper POCO object that contains that data to be serialized:
[Serializable]
internal class DataStoreContainer
{
public DataStoreContainer()
{
UserIDs = new List<int>();
}
public List<int> UserIDs { get; set; }
}
To consume these extensions:
private IsolatedStorageFile _isoStore = IsolatedStorageFile.GetStore(IsolatedStorageScope.User | IsolatedStorageScope.Assembly, null, null);
private DataStoreContainer _data = new DataStoreContainer();
private const string FILENAME = "MyAppName.dat";
And in any method where you want to get the data :
_data = _isoStore.LoadObject<DataStoreContainer>(FILENAME);
To save the data:
_isoStore.SaveObject(_data, FILENAME);
Have you looked at Isolated Storage? It stores data in a local file, specific to that user (or to the application, depending on how you specify). You can easily serialize objects to and from the store because it's stream-based. It sounds like the perfect solution for your problem.
Since you state 10 items would be a lot I would vote for #1 or a variation of #1, Binary serialized... you don't seem to indicate that being able to read the data is important and binary data should give you smaller file sizes, though if 10 is a lot this still shouldn't be important.
That being said I enjoy what I've seen of db4objects.

New Access database, how can it be done?

I have a project in C# using Microsoft Office Access for storage. I can read and save to the database.
Now I need to allow the user to use the new database project but structured like the working one, and also to implement Save As option.
Besides I need to export to a text file/CSV.
Any ideas or sample codes would be helpful.
One way to create a blank DB is to try the following
using System;
using ADOX;
public class CreateDB
{
public static void Main( string [] args )
{
ADOX.CatalogClass cat = new ADOX.CatalogClass();
string create =
#"Provider=Microsoft.Jet.OLEDB.4.0;Data
Source=C:\BlankAccessDB\MyAccessDBCreatedFromCsharp.mdb;" +
"Jet OLEDB:Engine Type=5";
cat.Create(create);
cat = null;
}
}
Both Save and SaveAs is as easy as using SaveFileDialog to prompt the user to specify the filename and location to save the file.
The way I did this was to create a new empty access database file (this comes to about 100 KB) and then embed that file as a resource in my application. To "create" a new database is then simply a matter of extracting the resource to a file - which gives you a blank database - and then running a schema update code to create the schema you require in the blank database and then off you go.
I have a project that contains an empty database set to be embedded, a class with one method as below and, er, that's about it.
This is the code to dump the file from the embedded resource - it's not up to date, I wrote it 6 years ago but have had no need to change it:
public void CreateDatabase(string sPath)
{
// Get the resource and, er write it out?
System.IO.Stream DBStream;
System.IO.StreamReader dbReader;
System.IO.FileStream OutputStream;
OutputStream = new FileStream(sPath, FileMode.Create);
Assembly ass = System.Reflection.Assembly.GetAssembly(this.GetType());
DBStream = ass.GetManifestResourceStream("SoftwareByMurph.blank.mdb");
dbReader = new StreamReader(DBStream);
for(int l=0;l < DBStream.Length;l++)
{
OutputStream.WriteByte((byte)DBStream.ReadByte());
}
OutputStream.Close();
}
Simple, effective and the .dll is 124 KB.
Note I use an utterly blank and empty Access file - attempting to maintain the right schema in the embedded file is going to cause it to grow (because of the way .mdb files work) and may result in shipping data - which probably shouldn't happen. The schema itself is created/updated/maintained by a separate lump of DDL (SQL) that I run from code.
Export to .CSV is moderately trivial to do by hand since you pretty much just need to iterate over the columns in a table but for a smarter approach look at FileHelpers.

Categories