Files and local storage – Windows Phone 7

Every mobile platform seems to have its own nuances for application data storage on the device. Typically I use some sort of file or database to store application data, and so there are three primary things I need to do.

1. Copy the ‘initial’ file from my application package to the device.
2. Read the file from the device as part of the program’s operation.
3. Update the file on the device when the user adds or updates data.

Since I had problems figuring out how to do this on every platform, I’m going to quickly document it. Since Windows Phone 7 is my most recent platform, I’ll start there. Look for Android and iOS (monotouch) versions of this coming soon.

These examples are a little more than just the file I/O lines of code, I have left the context of my read/write methods in place as well just in case that makes things clearer. I essentially have an xml file that contains all the ‘pre-loaded’ objects serialized. Over time, the user can ‘sync’ with a web service to get new items, which then get added to my saved xml file.

I cut and pasted a lot of the code I started with from web searches, but I didn’t keep track of who I borrowed which code from, so apologies to anyone who might be offended if they see something that looks like their blog post code below. Just know that I did not write all code myself from scratch, and leave it at that. =)

This is from my WP7 app Prayer Cookie

1. Copy the initial file at app startup. Use the App.xaml.cs events to trigger on Application_Launching like this: (note that in my case, I have a folder ‘Data’ in my XAP, with a file called ‘Prayers.xml’ packaged as a resource – I want to copy this to local storage as ‘Prayers.xml’)

        // Code to execute when the application is launching (eg, from Start)
        // This code will not execute when the application is reactivated
        private void Application_Launching(object sender, LaunchingEventArgs e)
        {
            //get the storage for your app 
            IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication();
            //define a StreamWriter
            StreamWriter writeFile = null;

            if (!store.FileExists("Prayers.xml"))
            {
                //Create a new file and use a StreamWriter to the store a new file in the directory we just created
                writeFile = new StreamWriter(new IsolatedStorageFileStream("Prayers.xml", FileMode.CreateNew, store));
            }

            if (!(writeFile == null))
            {
                //use a StreamReader to open and read the file           
                StreamReader readFile = null;
                readFile = new StreamReader(GetResourceStream(new Uri("Data/Prayers.xml", UriKind.Relative)).Stream);

                string fileText = readFile.ReadToEnd();

                writeFile.Write(fileText);
                writeFile.Close();
            }
        }

2. Read the file from device as needed by page(s)

        private void LoadPrayers()
        {
            //get the storage for your app 
            IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication();

            IsolatedStorageFileStream loadStream = store.OpenFile("Prayers.xml", FileMode.Open);

            var xElem = XElement.Load(loadStream);

            loadStream.Close();
            
            prayers =
                (from elem in xElem.Descendants("prayer")
                    //orderby elem.Element("id").Value
                select new Prayer
                {
                    id = Convert.ToInt32(elem.Element("id").Value),
                    text = elem.Element("text").Value
                }).ToList<Prayer>();
            
            maxPrayerId = prayers.Max(x => x.id);

            ApplicationTitle.Text = "Prayer Cookie (" + maxPrayerId.ToString() + " total)";
        }

3. Save a modified version of the file to the device when changes are made

        private void SavePrayers(List<Prayer> newPrayers)
        {
            try
            {
                var store = IsolatedStorageFile.GetUserStoreForApplication();
                StringBuilder sb = new StringBuilder();

                //serialize the new prayers
                foreach (Prayer current in newPrayers)
                {
                    sb.Append("<prayer><id>" + current.id.ToString() + "</id><text>" + current.text + "</text></prayer>");
                }

                //read the current text of the file
                StreamReader readFile = null;

                IsolatedStorageFileStream fileStream = store.OpenFile("Prayers.xml", FileMode.Open, FileAccess.Read);


                readFile = new StreamReader(fileStream);
                string fileText = readFile.ReadToEnd();

                readFile.Close();

                //insert the text for the new prayers
                fileText = fileText.Replace("</prayers>", sb.ToString() + "</prayers>");

                //delete, then save the file
                store.DeleteFile("Prayers.xml");

                StreamWriter writeFile = new StreamWriter(store.CreateFile("Prayers.xml"));

                if (!(writeFile == null))
                {
                    writeFile.Write(fileText);
                    writeFile.Close();
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "ERROR", MessageBoxButton.OK);
                Console.Error.WriteLine("Exception: " + ex.Message);
            }
        }