I am building my first WP8 application and I ran into a doubt.
I have to save in the IsolatedStorage some data obtained by serializing three different object.
My code for loading this data is this:
public static Statistics GetData()
{
Statistics data = new Statistics();
try
{
using (IsolatedStorageFile myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication())
{
using (IsolatedStorageFileStream stream = myIsolatedStorage.OpenFile("stats.xml", FileMode.OpenOrCreate))
{
XmlSerializer serializer = new XmlSerializer(typeof(Statistics));
data = (Statistics)serializer.Deserialize(stream);
}
}
}
catch (Exception e)
{
MessageBox.Show(e.Message + "\n" + e.InnerException);
}
return data;
}
And for saving data of course is this
public static void SaveStats(Statistics stats)
{
XmlWriterSettings xmlWriterSettings = new XmlWriterSettings();
xmlWriterSettings.Indent = true;
try
{
using (IsolatedStorageFile myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication())
{
using (IsolatedStorageFileStream stream = myIsolatedStorage.OpenFile("stats.xml", FileMode.Create))
{
XmlSerializer serializer = new XmlSerializer(typeof(Statistics));
using (XmlWriter xmlWriter = XmlWriter.Create(stream, xmlWriterSettings))
{
serializer.Serialize(xmlWriter, stats);
}
}
}
}
catch
{
MessageBox.Show("Salvataggio non riuscito");
}
}
This works fine, now the problem is that I have to do the same also for other two classes.
Do I have to write the same exact code again, only changing Statistics with the other class?
Or there is something way more clever to do?
Take a look at Generics.
Your serialize method would look like this:
public static void SaveStats<T>(T obj) where T : class, new()
{
...
XmlSerializer serializer = new XmlSerializer(typeof(T));
...
}
Method invoke:
SaveStats<Statistics>(new Statistics());
SaveStats<OtherObject>(new OtherObject());
Related
I´m building an GUI with Javafx and i was able to create a DataOutput to xml.
But now, i like to parse everything to JSON.
To save data to a File I used a Marshaller:
try {
JAXBContext context = JAXBContext
.newInstance(FirmenListWrapper.class);
Marshaller m = context.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
FirmenListWrapper wrapper = new FirmenListWrapper();
wrapper.setPersons(firmenData);
m.setProperty(MarshallerProperties.MEDIA_TYPE, "/json");
m.marshal(wrapper, file);
setFirmaFilePath(file);
} catch (Exception e) {
but it´s not working like this. Any Idea why?
my FirmenWrapper looks like this:
#XmlRootElement(name = "firmen")
public class FirmenListWrapper {
private List<Firmen> firmen;
#XmlElement(name = "firmen")
public List<Firmen> getFirmen() {
return firmen;
}
public void setFirmen(List<Firmen> firmen) {
this.firmen = firmen;
}
}
Thanks!
I would like to download a xml file from web, then save it to the local storage but I do not know how to do that. Please to help me clearly or give me an example. Thank you.
Downloading a file is a huge subject and can be done in many ways. I assume that you know the Uri of the file you want to download, and want you mean by local is IsolatedStorage.
I'll show three examples how it can be done (there are also other ways).
1. The simpliest example will dowload string via WebClient:
public static void DownloadFileVerySimle(Uri fileAdress, string fileName)
{
WebClient client = new WebClient();
client.DownloadStringCompleted += (s, ev) =>
{
using (IsolatedStorageFile ISF = IsolatedStorageFile.GetUserStoreForApplication())
using (StreamWriter writeToFile = new StreamWriter(ISF.CreateFile(fileName)))
writeToFile.Write(ev.Result);
};
client.DownloadStringAsync(fileAdress);
}
As you can see I'm directly downloading string (ev.Result is a string - that is a disadventage of this method) to IsolatedStorage.
And usage - for example after Button click:
private void Download_Click(object sender, RoutedEventArgs e)
{
DownloadFileVerySimle(new Uri(#"http://filedress/myfile.txt", UriKind.Absolute), "myfile.txt");
}
2. In the second method (simple but more complicated) I'll use again WebClient and I'll need to do it asynchronously (if you are new to this I would suggest to read MSDN, async-await on Stephen Cleary blog and maybe some tutorials).
First I need Task which will download a Stream from web:
public static Task<Stream> DownloadStream(Uri url)
{
TaskCompletionSource<Stream> tcs = new TaskCompletionSource<Stream>();
WebClient wbc = new WebClient();
wbc.OpenReadCompleted += (s, e) =>
{
if (e.Error != null) tcs.TrySetException(e.Error);
else if (e.Cancelled) tcs.TrySetCanceled();
else tcs.TrySetResult(e.Result);
};
wbc.OpenReadAsync(url);
return tcs.Task;
}
Then I'll write my method downloading a file - it also need to be async as I'll use await DownloadStream:
public enum DownloadStatus { Ok, Error };
public static async Task<DownloadStatus> DownloadFileSimle(Uri fileAdress, string fileName)
{
try
{
using (Stream resopnse = await DownloadStream(new Uri(#"http://filedress/myfile.txt", UriKind.Absolute)))
using (IsolatedStorageFile ISF = IsolatedStorageFile.GetUserStoreForApplication())
{
if (ISF.FileExists(fileName)) return DownloadStatus.Error;
using (IsolatedStorageFileStream file = ISF.CreateFile(fileName))
resopnse.CopyTo(file, 1024);
return DownloadStatus.Ok;
}
}
catch { return DownloadStatus.Error; }
}
And usage of my method for example after Button click:
private async void Downlaod_Click(object sender, RoutedEventArgs e)
{
DownloadStatus fileDownloaded = await DownloadFileSimle(new Uri(#"http://filedress/myfile.txt", UriKind.Absolute), "myfile.txt");
switch (fileDownloaded)
{
case DownloadStatus.Ok:
MessageBox.Show("File downloaded!");
break;
case DownloadStatus.Error:
default:
MessageBox.Show("There was an error while downloading.");
break;
}
}
This method can have problems for example if you try to download very big file (example 150 Mb).
3. The third method - uses WebRequest with again async-await, but this method can be changed to download files via buffer, and therefore not to use too much memory:
First I'll need to extend my Webrequest by a method that will asynchronously return a Stream:
public static class Extensions
{
public static Task<Stream> GetRequestStreamAsync(this WebRequest webRequest)
{
TaskCompletionSource<Stream> taskComplete = new TaskCompletionSource<Stream>();
webRequest.BeginGetRequestStream(arg =>
{
try
{
Stream requestStream = webRequest.EndGetRequestStream(arg);
taskComplete.TrySetResult(requestStream);
}
catch (Exception ex) { taskComplete.SetException(ex); }
}, webRequest);
return taskComplete.Task;
}
}
Then I can get to work and write my Downloading method:
public static async Task<DownloadStatus> DownloadFile(Uri fileAdress, string fileName)
{
try
{
WebRequest request = WebRequest.Create(fileAdress);
if (request != null)
{
using (Stream resopnse = await request.GetRequestStreamAsync())
{
using (IsolatedStorageFile ISF = IsolatedStorageFile.GetUserStoreForApplication())
{
if (ISF.FileExists(fileName)) return DownloadStatus.Error;
using (IsolatedStorageFileStream file = ISF.CreateFile(fileName))
{
const int BUFFER_SIZE = 10 * 1024;
byte[] buf = new byte[BUFFER_SIZE];
int bytesread = 0;
while ((bytesread = await resopnse.ReadAsync(buf, 0, BUFFER_SIZE)) > 0)
file.Write(buf, 0, bytesread);
}
}
return DownloadStatus.Ok;
}
}
return DownloadStatus.Error;
}
catch { return DownloadStatus.Error; }
}
Again usage:
private async void Downlaod_Click(object sender, RoutedEventArgs e)
{
DownloadStatus fileDownloaded = await DownloadFile(new Uri(#"http://filedress/myfile.txt", UriKind.Absolute), "myfile.txt");
switch (fileDownloaded)
{
case DownloadStatus.Ok:
MessageBox.Show("File downloaded!");
break;
case DownloadStatus.Error:
default:
MessageBox.Show("There was an error while downloading.");
break;
}
}
Those methods of course can be improved but I think this can give you an overview how it can look like. The main disadvantage of these methods may be that they work in foreground, which means that when you exit your App or hit start button, downloading stops. If you need to download in background you can use Background File Transfers - but that is other story.
As you can see you can reach your goal in many ways. You can read more about those methods on many pages, tutorials and blogs, compare an choose the most suitable.
Hope this helps. Happy coding and good luck.
I'm developing my first Windows Store App, using MvvmCross framework and I have a problem with images management. In particular I have the following simple ViewModel in my PCL project, and a Store project with a button bound with AddPictureCommand.
public class FirstViewModel : MvxViewModel
{
IMvxPictureChooserTask _pictureChooserTask;
IMvxFileStore _fileStore;
public FirstViewModel(IMvxPictureChooserTask pictureChooserTask, IMvxFileStore fileStore)
{
_pictureChooserTask = pictureChooserTask;
_fileStore = fileStore;
}
private byte[] _pictureBytes;
public byte[] PictureBytes
{
get { return _pictureBytes; }
set
{
if (_pictureBytes == value) return;
_pictureBytes = value;
RaisePropertyChanged(() => PictureBytes);
}
}
public ICommand AddPictureCommand
{
get { return new MvxCommand(() =>
{
_pictureChooserTask.ChoosePictureFromLibrary(400, 95, pictureAvailable, () => { });
}); }
}
private void pictureAvailable(Stream stream)
{
MemoryStream memoryStream = new MemoryStream();
stream.CopyTo(memoryStream);
PictureBytes = memoryStream.ToArray();
GenerateImagePath();
}
private string GenerateImagePath()
{
if (PictureBytes == null) return null;
var RandomFileName = "Image" + Guid.NewGuid().ToString("N") + ".jpg";
_fileStore.EnsureFolderExists("Images");
var path = _fileStore.PathCombine("Images", RandomFileName);
_fileStore.WriteFile(path, PictureBytes);
return path;
}
}
The problem is that the method _fileStore.EnsureFolderExists("Images");
gives me the an "NotImplementedException" with message: "Need to implement this - doesn't seem obvious from the StorageFolder API".
Has anyone already seen it before?
Thank you
This not implemented exception is documented in the wiki - see https://github.com/MvvmCross/MvvmCross/wiki/MvvmCross-plugins#File
It should be fairly straightforward to implement these missing methods if they are required. Indeed I know of at least 2 users that have implemented these - but sadly they've not contributed them back.
to implement them, just
fork (copy) the code from https://github.com/MvvmCross/MvvmCross/blob/v3/Plugins/Cirrious/File/Cirrious.MvvmCross.Plugins.File.WindowsStore/MvxWindowsStoreBlockingFileStore.cs
implement the missing methods using the winrt StorageFolder apis
in your Store UI project, don't load the File plugin - so comment out or remove the File bootstrap class.
during setup, register your implementation with ioc using Mvx.RegisterType - e.g.:
protected override void InitializeFirstChance()
{
base.InitializeFirstChance();
Cirrious.CrossCore.Mvx.RegisterType<IMvxFileStore, MyFileStore>();
}
For more on using ioc, see https://github.com/MvvmCross/MvvmCross/wiki/Service-Location-and-Inversion-of-Control
For more on customising the setup sequence, see https://github.com/MvvmCross/MvvmCross/wiki/Customising-using-App-and-Setup
Following Stuart's suggestions I've implemented the following methods for Windows 8 Store App:
public bool FolderExists(string folderPath)
{
try
{
var directory = ToFullPath(folderPath);
var storageFolder = StorageFolder.GetFolderFromPathAsync(directory).Await();
}
catch (FileNotFoundException)
{
return false;
}
catch (Exception ex)
{
MvxTrace.Trace("Exception in FolderExists - folderPath: {0} - {1}", folderPath, ex.ToLongString());
throw ex;
}
return true;
//throw new NotImplementedException("Need to implement this - See EnsureFolderExists");
}
public void EnsureFolderExists(string folderPath)
{
try
{
var directory = ToFullPath(folderPath);
var storageFolder = StorageFolder.GetFolderFromPathAsync(directory).Await();
}
catch (FileNotFoundException)
{
var localFolder = ToFullPath(string.Empty);
var storageFolder = StorageFolder.GetFolderFromPathAsync(localFolder).Await();
storageFolder.CreateFolderAsync(folderPath).Await();
}
catch (Exception ex)
{
MvxTrace.Trace("Exception in EnsureFolderExists - folderPath: {0} - {1}", folderPath, ex.ToLongString());
throw ex;
}
//throw new NotImplementedException("Need to implement this - doesn't seem obvious from the StorageFolder API");
//var folder = StorageFolder.GetFolderFromPathAsync(ToFullPath(folderPath)).Await();
}
The third method we need to implement is DeleteFolder(string folderPath, bool recursive). Unfortunately StorageFolder method "DeleteFolder" doesn't have a "recursive" parameter. So I should implement DeleteFolder ignoring it:
public void DeleteFolder(string folderPath, bool recursive)
{
try
{
var directory = ToFullPath(folderPath);
var storageFolder = StorageFolder.GetFolderFromPathAsync(directory).Await();
storageFolder.DeleteAsync().Await();
}
catch (FileNotFoundException)
{
//Folder doesn't exist. Nothing to do
}
catch (Exception ex)
{
MvxTrace.Trace("Exception in DeleteFolder - folderPath: {0} - {1}", folderPath, ex.ToLongString());
throw ex;
}
//throw new NotImplementedException("Need to implement this - See EnsureFolderExists");
}
or I should check if the folder is empty before to delete it if "recursive" equals false.
Better implementations are welcomed.
Given some list of objects:
List<Car> carlist = new List<Car>();
How can I serialize this list as an XML or binary file and deserialize it back?
I have this so far but it doesn't work.
//IsolatedStorageFile isFile = IsolatedStorageFile.GetUserStoreForApplication();
//IsolatedStorageFileStream ifs = new IsolatedStorageFileStream("myxml.xml", FileMode.Create,isFile);
//DataContractSerializer ser = new DataContractSerializer();
//XmlWriter writer = XmlWriter.Create(ifs);
//ser.WriteObject(writer, carlist);
I'm using these methods to Save and Load from a XML file in/to the IsolatedStorage :
public static class IsolatedStorageOperations
{
public static async Task Save<T>(this T obj, string file)
{
await Task.Run(() =>
{
IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForApplication();
IsolatedStorageFileStream stream = null;
try
{
stream = storage.CreateFile(file);
XmlSerializer serializer = new XmlSerializer(typeof (T));
serializer.Serialize(stream, obj);
}
catch (Exception)
{
}
finally
{
if (stream != null)
{
stream.Close();
stream.Dispose();
}
}
});
}
public static async Task<T> Load<T>(string file)
{
IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForApplication();
T obj = Activator.CreateInstance<T>();
if (storage.FileExists(file))
{
IsolatedStorageFileStream stream = null;
try
{
stream = storage.OpenFile(file, FileMode.Open);
XmlSerializer serializer = new XmlSerializer(typeof (T));
obj = (T) serializer.Deserialize(stream);
}
catch (Exception)
{
}
finally
{
if (stream != null)
{
stream.Close();
stream.Dispose();
}
}
return obj;
}
await obj.Save(file);
return obj;
}
}
You can customize the error handling in the catch().
Also, you can adjust the Load method to your needs, in my case I am trying to load from a file and if doesn't exist, it creates a default one and puts the default serialized object of the type provided according to the constructor.
UPDATE :
Let's say you have that list of cars :
List< Car > carlist= new List< Car >();
To save, you can just call them as await carlist.Save("myXML.xml"); , as it is an asynchronous Task(async).
To load, var MyCars = await IsolatedStorageOperations.Load< List< Car> >("myXML.xml"). (I think, I haven't used it like this, as a List so far...
DataContactJsonSerializer performs better than XmlSerializer. It creates smaller files and handles well lists inside properties.
I'm working on a 2D mobile game for ios and android using Unity3D.
The game requires to save a JSON response to a file.
I use NGUI and MiniJSON for that.
I want to know how to implement that starting from www function to get JSOn response and save it to a file(including path) and load it from other script.
if it is too much, just give me a example for that.
Thank you
I haven't tested the code yet, but it might give you an idea :-)
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.IO;
public class WWWJsonTest : MonoBehaviour
{
private const float SECONDS_BEFORE_TIMEOUT = 10;
private const string URL = "INSERT URL HERE";
private const string FILE_PATH = "INSERT FILE PATH";
public void DownloadAndSave()
{
StartCoroutine(DownloadCoroutine());
}
public Dictionary<object, object> GetSavedData()
{
// Use ReadContents() and do your MiniJSON magic here
return null;
}
private IEnumerator DownloadCoroutine()
{
var requestHeaders = new Hashtable()
{
{ "Connection", "close"},
{ "Accept", "application/json"}
};
using(var request = new WWW(URL, null, requestHeaders))
{
float timeStarted = Time.realtimeSinceStartup;
while(!request.isDone)
{
// Check if the download times out
if(Time.realtimeSinceStartup - timeStarted > SECONDS_BEFORE_TIMEOUT)
{
Debug.Log("Download timed out");
yield break;
}
yield return null;
}
// Check for other errors
if(request.error != null)
{
Debug.Log(request.error);
yield break;
}
SaveContents(request.text);
}
}
private string ReadContents()
{
string ret;
using(FileStream fs = new FileStream(FILE_PATH, FileMode.Open))
{
BinaryReader fileReader = new BinaryReader(fs);
ret = fileReader.ReadString();
fs.Close();
}
return ret;
}
private void SaveContents(string text)
{
using(FileStream fs = new FileStream(FILE_PATH, FileMode.Create))
{
BinaryWriter fileWriter = new BinaryWriter(fs);
fileWriter.Write(text);
fs.Close();
}
}
}