User Tools

Site Tools


notes:uwp:appdata

Data in UWP

The ApplicationData class represents the Application Local Storage area on the hard drive that is private to an app. It contains folders where the app can store data. These folders (local, roaming and temporary) are created when the app is installed.

You can't access the local, roaming, or temporary folders through the file picker.

Obtain app data folders:

using Windows.Storage;
...
// Obtain the ApplicationData object for the current application.
ApplicationData appData = ApplicationData.Current;
 
// Obtain app data folders.
StorageFolder localFolder = ApplicationData.Current.LocalFolder;
StorageFolder roamingFolder = ApplicationData.Current.RoamingFolder;
StorageFolder temporaryFolder = ApplicationData.Current.TemporaryFolder;

Obtain the path to the local folder:

string path = ApplicationData.Current.LocalFolder.Path;

StorageFile & StorageFolder

You can manage files using the methods of the StorageFile and StorageFolder classes.

var localFolder = ApplicationData.Current.LocalFolder;
 
// Create a new file or open an existing one.
StorageFile file = await localFolder.CreateFileAsync("data.txt", CreationCollisionOption.OpenIfExists);
 
// Create a new file or override an existing one.
StorageFile file = await localFolder.CreateFileAsync("data.txt", CreationCollisionOption.ReplaceExisting);
 
// Create a new file with a unique name.
StorageFile file = await localFolder.CreateFileAsync("data.txt", CreationCollisionOption.GenerateUniqueName); 
 
// Obtain a file by its name.
StorageFile file = await localFolder.GetFileAsync("data.txt");
 
// Obtain a file by its full path.
string path = System.IO.Path.Combine(localFolder.Path, "data.txt");
StorageFile file = await StorageFile.GetFileFromPathAsync(path);
 
// Delete all package files.
await ApplicationData.Current.ClearAsync();
 
// Obtain all files located in a given folder.
IReadOnlyList<StorageFile> files = await localFolder.GetFilesAsync()

The StorageFile class provides the GetFileFromApplicationUriAsync method as well as the GetFileFromPathAsync method to load files using URIs.

FileIO, FolderIO, PathIO

Static methods FileIO, FolderIO, and PathIO are not suitable for working with large files because they read the whole file into memory all at once.

Append a string to a text file. It's useful for a quick logging mechanism:

string str = "Test";
StorageFile file = 
   await ApplicationData.Current.LocalFolder.CreateFileAsync("test.txt", CreationCollisionOption.OpenIfExists);
await FileIO.AppendTextAsync(file, str, Windows.Storage.Streams.UnicodeEncoding.Utf8);

Read from a text file:

// Read an entire file as a single string.
string data = await FileIO.ReadTextAsync(file);
 
// Read an entire file as a list of strings. Each string should be separated by a NewLine character.
IList<string> list = await FileIO.ReadLinesAsync(file);

Write data to a binary file:

using Windows.Storage;
using Windows.Storage.Streams;
...
// Create a new file.
StorageFolder localFolder = ApplicationData.Current.LocalFolder;
StorageFile file = await localFolder.CreateFileAsync("data.bin", CreationCollisionOption.ReplaceExisting);
 
// Write to the binary file.
using (DataWriter writer = new DataWriter())
{
    // Write binary data to DataWriter.
    // DataWriter stores data in an internal IBuffer.
    writer.WriteBytes(new byte[] { 120, 34, 18, 234, 68 });
 
    // Write data from the internal IBuffer to the binary file.
    await FileIO.WriteBufferAsync(file, writer.DetachBuffer());
}

Prepare binary data in a separate method (GetBuffer) and write it to a file:

using Windows.Storage;
using Windows.Storage.Streams;
...
private async void WriteToBinaryFile()
{
    // Create a new file.
    StorageFolder localFolder = ApplicationData.Current.LocalFolder;
    StorageFile file = await localFolder.CreateFileAsync("data.bin", CreationCollisionOption.ReplaceExisting);
 
    await FileIO.WriteBufferAsync(file, GetBuffer());
}
 
// A helper method to prepare a buffer with binary data.
private IBuffer GetBuffer()
{
    IBuffer buffer;
 
    using (DataWriter writer = new DataWriter())
    {
        writer.WriteBytes(new byte[] { 120, 34, 18, 234, 68 });
        buffer = writer.DetachBuffer();
    }
 
    return buffer;
}

Read data from a binary file:

using Windows.Storage;
using Windows.Storage.Streams;
...
StorageFolder localFolder = ApplicationData.Current.LocalFolder;
StorageFile file = await localFolder.GetFileAsync("data.bin");
 
IBuffer buffer = await FileIO.ReadBufferAsync(file);
using (DataReader reader = DataReader.FromBuffer(buffer))
{
    // Read data from DataReader.
    byte[] data = new byte[buffer.Length];
    reader.ReadBytes(data);
 
    // Display data in the Debug window.
    foreach (byte b in data)
        Debug.WriteLine(b);
}

Read data from a binary file using a .NET class System.IO.BinaryReader and the extension method AsStreamForRead:

using System.IO;
using Windows.Storage;
using Windows.Storage.Streams;
...
StorageFolder localFolder = ApplicationData.Current.LocalFolder;
StorageFile file = await localFolder.GetFileAsync("data.bin");
 
// The OpenReadAsync method opens a random-access stream over the current file for reading file contents.
// When the method completes, it returns the random-access stream of type IRandomAccessStreamWithContentType.
IRandomAccessStreamWithContentType stream = await file.OpenReadAsync();
stream.Seek(0);
BinaryReader reader = new BinaryReader(stream.AsStreamForRead());
byte[] buffer = new byte[stream.Size];
reader.Read(buffer, 0, buffer.Length);

Methods of a static PathIO class are identical to those of the FileIO class except that the methods accept an absolute path string instead of an IStorageFile.

// Write the lines.
StorageFile file = await ApplicationData.Current.LocalFolder.CreateFileAsync("data.txt");  
String[] output = new[] { "Line 1", "Line 2" }; 
await PathIO.WriteLinesAsync(file.Path, output); 
 
// Read the lines from the file (decoded with UTF-8): 
IList<String> input = await PathIO.ReadLinesAsync(file.Path);
// Read data from a location provided as an URI.
var buffer = await PathIO.ReadBufferAsync(uri);

FileIO methods:

  • AppendLinesAsync
  • AppendTextAsync
  • ReadLinesAsync
  • ReadTextAsync
  • ReadBufferAsync
  • WriteLinesAsync
  • WriteTextAsync
  • WriteBufferAsync
  • WriteBytesAsync

A few traits of IBuffer:

  • Represents an array of bytes in system memory.
  • Provides a convenient way to transfer bytes from one stream to another.
  • It is possible to convert IBuffer to an array of bytes.
  • Defines two properties: Capacity and Length.
  • The ReadAsync method defined by the IInputStream interface reads from a stream into an IBuffer.
  • The WriteAsync method defined by the IOutputStream interface writes from the IBuffer into the stream.

DataReader and DataWriter

The Windows.Storage.Streams.DataWriter and Windows.Storage.Streams.DataReader classes are equivalent of the .NET System.IO.BinaryWriter and System.IO.BinaryReader classes for storing and retrieving primitive data types from a stream.

Example: Write and read from a stream:

using Windows.Storage;
using Windows.Storage.Streams;
...
StorageFolder localFolder = ApplicationData.Current.LocalFolder;
StorageFile file = await localFolder.CreateFileAsync("data.dat", CreationCollisionOption.ReplaceExisting);
 
using (var writer = new DataWriter(await file.OpenAsync(FileAccessMode.ReadWrite)))
{
    writer.WriteBytes(new Byte[] { 8, 6, 4 });
 
    const string str = "Testing";
 
    // MeasureString returns how many bytes a string requires when encoded via UnicodeEncoding.
    uint len = writer.MeasureString(str); // measure the string taking into account encoding (why 7?)
    writer.WriteUInt32(len); // store the string length
    writer.WriteString(str); // store the string
 
    uint bytesStored = await writer.StoreAsync(); // commit buffer to the stream
    Debug.WriteLine($"Bytes stored: {bytesStored}"); // 14
} // close DataWriter and the underlying stream
 
 
// LoadAsync reads count bytes from stream appending them to the buffer.
using (var reader = new DataReader(await file.OpenAsync(FileAccessMode.Read)))
{
    byte[] bytes = new byte[3];
    uint bytesRead = await reader.LoadAsync((uint)bytes.Length);
    reader.ReadBytes(bytes);
 
    // Get the length of the string.
    bytesRead = await reader.LoadAsync(sizeof(uint));
    var len = reader.ReadUInt32();
 
    // Read the string.
    bytesRead = await reader.LoadAsync(len);
    string str = reader.ReadString(len);
    Debug.WriteLine($"String: {str}");
} // close DataReader and the underlying stream

Links

Application URI

You can access files using the StorageFile.GetFileFromApplicationUriAsync method and providing a URI with the ms-appdata:/// prefix.

Folder URI Prefix
LocalFolder ms-appdata:///local
RoamingFolder ms-appdata:///roaming
TemporaryFolder ms-appdata:///temp
InstallFolder ms-appx:///
// Retrieve a file test.txt located in ApplicationData.Current.LocalFolder.
StorageFile file = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appdata:///local/test.txt"));

ms-appx-web points to resources stored in the app's package for use in web scenarios; it accesses the same files as ms-appx but in the web compartment.

Copying Files

Copy a file from the installation folder to the local folder:

// sourcePath is the path of a file in the installation folder. It must be prefixed with ms-appx:/// 
string sourcePath = "ms-appx:///data.txt";
 
// destFilename is the desired name of the filename in the local folder.
string destFilename = "data.txt";
 
// Obtain a file from the installation folder.
StorageFile file = await StorageFile.GetFileFromApplicationUriAsync(new Uri(sourcePath));
 
// Copy the file to the local folder.
await file.CopyAsync(Windows.Storage.ApplicationData.Current.LocalFolder, 
    destFilename, NameCollisionOption.ReplaceExisting);

Installed Location

Set a file's Build Action property to Content in order to access the file in the code.

Example: Access a file in the install directory (the package's directory):

using Windows.Storage;
...
// Method #1
StorageFolder folder = Windows.ApplicationModel.Package.Current.InstalledLocation;
StorageFile file = await folder.GetFileAsync(@"Assets\Image.png");
 
// Method #2
StorageFile file = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Assets/image.png"));

Note that ms-appx:///Assets/image.png is equivalent to

"ms-appx://" + Windows.ApplicationModel.Package.Current.Id.Name + "/Assets/image.png"

Serialization

Example: An exmaple of XML serialization.

This program provides two buttons:

  • The [Save Books] button serializes a bunch of book objects (represented as a BookModel class) to individual XML files, one file for each book.
  • The [Load Books] button deserializes books from XML files to a collection.
<Page x:Class="TestApp.MainPage"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
 
    <Grid>
        <StackPanel>
            <Button Content="Save Books" Margin="16" Click="SaveBooksButton_Click" />
            <Button Content="Load Books" Margin="16" Click="LoadBooksButton_Click" />
        </StackPanel>
    </Grid>
</Page>
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Runtime.Serialization;
using System.Threading.Tasks;
using Windows.Storage;
using Windows.Storage.Search; // StorageFileQueryResult
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
 
namespace TestApp
{
    [DataContract(Name = "Book")]
    public class BookModel
    {
        [DataMember]
        public int Id { get; set; }
        [DataMember]
        public string Title { get; set; }
        [DataMember]
        public string Author { get; set; }
 
        public override string ToString()
        {
            return String.Format("Id = {0}, Title = {1}, Author = {2}", Id, Title, Author);
        }
    }
 
    public sealed partial class MainPage : Page
    {
        public MainPage()
        {
            this.InitializeComponent();
        }
 
        private async void SaveBooksButton_Click(object sender, RoutedEventArgs e)
        {
            await SaveBookAsync(new BookModel { Id = 1, Title = "Book1", Author = "Author1" }, "book1.xml");
            await SaveBookAsync(new BookModel { Id = 2, Title = "Book2", Author = "Author2" }, "book2.xml");
            await SaveBookAsync(new BookModel { Id = 3, Title = "Book3", Author = "Author3" }, "book3.xml");
        }
 
        private async void LoadBooksButton_Click(object sender, RoutedEventArgs e)
        {
            IEnumerable<BookModel> books = await GetBooksAsync();
            foreach (BookModel book in books)
                Debug.WriteLine(book.ToString());
        }
 
        public async Task SaveBookAsync(BookModel book, string filename)
        {
            var knownTypes = new Type[]
            {
                typeof(BookModel)
            };
 
            var ser = new DataContractSerializer(typeof(BookModel), knownTypes);
 
            // Create the data file.
            StorageFolder folder = ApplicationData.Current.LocalFolder;
            StorageFile file = await folder.CreateFileAsync(filename, CreationCollisionOption.ReplaceExisting);
 
            using (MemoryStream ms = new MemoryStream())
            {
                // Fill the .NET memory stream with data.
                ser.WriteObject(ms, book);
 
                // Use the extension method OpenStreamForWriteAsync to obtain the .NET stream.
                using (Stream fs = await file.OpenStreamForWriteAsync())
                {
                    ms.Seek(0, SeekOrigin.Begin);
                    await ms.CopyToAsync(fs);
                    await fs.FlushAsync();
                }
            }
        }
 
        public async Task<IEnumerable<BookModel>> GetBooksAsync()
        {
            IList<BookModel> items = new List<BookModel>();
 
            StorageFolder folder = ApplicationData.Current.LocalFolder;
 
            StorageFileQueryResult result = folder.CreateFileQuery();
            var options = new QueryOptions();
            options.IndexerOption = IndexerOption.DoNotUseIndexer; // access the file system directly
            options.FolderDepth = FolderDepth.Shallow;
            options.FileTypeFilter.Add(".xml");
            result.ApplyNewQueryOptions(options);
 
            IReadOnlyList<StorageFile> files = await result.GetFilesAsync();
 
            foreach (StorageFile file in files)
            {
                using (Stream stream = await file.OpenStreamForReadAsync())
                {
                    var ser = new DataContractSerializer(typeof(BookModel));
                    object data = await Task<object>.Run(() => ser.ReadObject(stream));
                    items.Add(data as BookModel);
                }
            }
 
            return items;
        }
    }
}

KnownFolders

Known Folder Description
DocumentsLibrary Gets the Documents library
HomeGroup Gets the HomeGroup folder
MediaServerDevices Gets the Media Server Devices (Digital Living Network Alliance [DLNA]) folder
MusicLibrary Gets the Music library
PicturesLibrary Gets the Pictures library
RemovableDevices Gets the Removable Devices folder
VideosLibrary Gets the Videos library

Example: Display a flat list of files located in the PicturesLibrary folder and its subfolders.

You can use the APIs in the Windows.Storage namespace to retrieve folder and file data. However, the various GetFilesAsync, GetFoldersAsync, and GetItemsAsync methods do not return values that are suitable for binding to list controls. Instead, you must bind to the return values of the GetVirtualizedFilesVector, GetVirtualizedFoldersVector, and GetVirtualizedItemsVector methods of the FileInformationFactory class.

<ListView x:Name="PicturesListView" Height="300" DisplayMemberPath="DisplayName" />
var library = Windows.Storage.KnownFolders.PicturesLibrary;
var queryOptions = new Windows.Storage.Search.QueryOptions();
queryOptions.FolderDepth = Windows.Storage.Search.FolderDepth.Deep;
queryOptions.IndexerOption = Windows.Storage.Search.IndexerOption.UseIndexerWhenAvailable;
 
var query = library.CreateFileQueryWithOptions(queryOptions);
 
var info = new Windows.Storage.BulkAccess.FileInformationFactory(
    query,
    Windows.Storage.FileProperties.ThumbnailMode.PicturesView,
    190,
    Windows.Storage.FileProperties.ThumbnailOptions.UseCurrentScale,
    false);
 
var dataSource = info.GetVirtualizedFilesVector();
 
PicturesListView.ItemsSource = dataSource;

Indexed Folder

Windows Search does not index the contents of your package's folders (more details here). However, if you create a folder called “Indexed” in your package's local folder, Windows Search will index the contents of this folder.

Example: Create the “Indexed” folder, add two text files to it, and then perform a query against the folder:

// Create the "Indexed" subdirectory in the Local package folder. 
StorageFolder localFolder = ApplicationData.Current.LocalFolder;
StorageFolder indexed = await localFolder.CreateFolderAsync("Indexed");
 
// Create two text files in the "Indexed" subdirectory: 
await FileIO.WriteTextAsync(await indexed.CreateFileAsync("data1.txt"), "aa bb cc");
await FileIO.WriteTextAsync(await indexed.CreateFileAsync("data2.txt"), "aa dd ee");
 
// Create a query that looks for .txt files containing "dd" 
var query = new QueryOptions(CommonFileQuery.DefaultQuery, new[] { ".txt" })
{
    ApplicationSearchFilter = "dd",
    IndexerOption = IndexerOption.OnlyUseIndexer, // use indexed files only 
    FolderDepth = FolderDepth.Deep // search subdirectories too 
};
 
StorageFileQueryResult results = localFolder.CreateFileQueryWithOptions(query);
 
// Perform the query and get the results.
IReadOnlyList<StorageFile> result = await results.GetFilesAsync(); 
 
// 'result' is a list containing a single StorageFile - data2.txt

Semaphore

Example: Write a piece of text to a file in a multithreaded environemnt:

private SemaphoreSlim mutex = new SemaphoreSlim(1);
public async void WriteLine(string str)
{
    await mutex.WaitAsync();
    try
    {
        // Create a new file or return an existing file if it already exists.
        var folder = ApplicationData.Current.LocalFolder;
        StorageFile file = await folder.CreateFileAsync("data.txt", CreationCollisionOption.OpenIfExists);
 
        await FileIO.AppendTextAsync(file, str);
    }
    finally
    {
        mutex.Release();
    }
}

More info on that here.

Storage Object Model

  • IStorageItem exposes members that operate on both files and folders:
public interface IStorageItem
{
    FileAttributes Attributes { get; }  // FileAttributes.ReadOnly, FileAttributes.Archive, etc.
    DateTimeOffset DateCreated { get; } // 7/26/2016 10:50:00 AM -06:00
    System.String Name { get; }         // picture.jpg
    System.String Path { get; }         // C:\Pictures\picture.jpg
 
    IAsyncAction DeleteAsync();
    IAsyncAction DeleteAsync(StorageDeleteOption option);
    IAsyncOperation<BasicProperties> GetBasicPropertiesAsync();
    bool IsOfType(StorageItemTypes type);
    IAsyncAction RenameAsync(string desiredName);
    IAsyncAction RenameAsync(string desiredName, NameCollisionOption option);
}
  • IStorageFolder inherits from IStorageItem and adds members that are specific to folders:
public interface IStorageFolder : IStorageItem
{
    IAsyncOperation<StorageFile> CreateFileAsync(string desiredName);
    IAsyncOperation<StorageFile> CreateFileAsync(string desiredName, CreationCollisionOption options);
    IAsyncOperation<StorageFolder> CreateFolderAsync(string desiredName);
    IAsyncOperation<StorageFolder> CreateFolderAsync(string desiredName, CreationCollisionOption options);
    IAsyncOperation<StorageFile> GetFileAsync(string name);
    IAsyncOperation<IReadOnlyList<StorageFile>> GetFilesAsync();
    IAsyncOperation<StorageFolder> GetFolderAsync(string name);
    IAsyncOperation<IReadOnlyList<StorageFolder>> GetFoldersAsync();
    IAsyncOperation<IStorageItem> GetItemAsync(string name);
    IAsyncOperation<IReadOnlyList<IStorageItem>> GetItemsAsync();
}
  • IStorageFile also inherits from IStorageItem and adds members that are specific to files:
public interface IStorageFile : IStorageItem, IRandomAccessStreamReference, IInputStreamReference
{
    string ContentType { get; } // .image/jpeg
    string FileType { get; }    // .jpg
 
    IAsyncAction CopyAndReplaceAsync(IStorageFile fileToReplace);
    IAsyncOperation<StorageFile> CopyAsync(IStorageFolder destinationFolder);
    IAsyncOperation<StorageFile> CopyAsync(IStorageFolder destinationFolder, string desiredNewName);
    IAsyncOperation<StorageFile> CopyAsync(IStorageFolder destinationFolder, string desiredNewName,
        NameCollisionOption option);
    IAsyncAction MoveAndReplaceAsync(IStorageFile fileToReplace);
    IAsyncAction MoveAsync(IStorageFolder destinationFolder);
    IAsyncAction MoveAsync(IStorageFolder destinationFolder, string desiredNewName);
    IAsyncAction MoveAsync(IStorageFolder destinationFolder, string desiredNewName, 
        NameCollisionOption option);
    IAsyncOperation<IRandomAccessStream> OpenAsync(FileAccessMode accessMode);
    IAsyncOperation<StorageStreamTransaction> OpenTransactedWriteAsync();
}
  • IStorageItemProperties defines members that expose a storage item's properties, such as:
    • thumbnail image
    • DisplayName (example: picture)
    • DisplayType (example: JPEG image)
    • FolderRelativeId (example: 4DE1A7035B395E15\\picture.JPG)

Use the GetScaledImageAsThumbnailAsync method of the IStorageItemProperties2 interface to obtain a file's thumbnail rather than the obsolete IStorageItemProperties.GetThumbnailAsync method. The IStorageItemProperties2 interface is implemented by both StorageFile and StorageFolder.

  • IStorageFolderQueryOperations exposes a set of operations for querying files and folders. Because a query is initiated via a root folder, only the StorageFolder class implements this interface.
  • StorageFolder is the concrete class that implements IStorageFolder, IStorageItem, IStorageItemProperties, and IStorageFolderQueryOperations. A StorageFolder may represent a physical folder on disk or a virtual folder.
  • StorageFile is the concrete class that implements IStorageFile, IStorageItem, and IStorageItemProperties. A StorageFile represents a file on disk.
  • A BasicProperties object exposes properties common to both files and folders:
    • DateModified (of type DateTimeOffset)
    • ItemDate (of type DateTimeOffset) - date released (for a song) or date taken (for a photo) etc.
    • Size (of type UInt64) - the size of the file
notes/uwp/appdata.txt · Last modified: 2017/02/27 by admin