The XNA Framework provides no less than three different APIs for reading data out of files. This table attempts to explain the differences, and thus help you understand which to choose:
Title Container | Isolated Storage | Storage Container | |
Purpose | Read content that was created by the developer and deployed as part of the game | Read and write game save data in a simple, cross platform way | Read and write game save data using a more complex and powerful API that provides more control over how save games appear in the Xbox dashboard, but which is not supported on Windows Phone |
Supported platforms | Windows, Windows Phone, Xbox 360 | Windows (kinda: stay tuned for my next post), Windows Phone, Xbox 360 | Windows, Xbox 360 |
Data created by | The developer at build time (games cannot write to the title container at runtime) | The game at runtime | The game at runtime |
Provided by | XNA Framework | .NET Framework | XNA Framework |
API | TitleContainer.OpenStream | IsolatedStorageFile.GetUserStoreForApplication | StorageDevice.BeginShowSelector, StorageDevice.EndShowSelector, StorageDevice.BeginOpenContainer, StorageDevice.EndOpenContainer, StorageContainer.OpenFile |
Example code | http://msdn.microsoft.com/en-us/library/bb199094.aspx | http://msdn.microsoft.com/en-us/library/ff604992.aspx |
Note that I did not include ContentManager.Load in this table, although that is probably the most commonly used API for loading data into XNA games! There is an important but easily missed layering here:
The aforementioned three APIs are responsible for opening streams that can be used to read sequences of bytes from a filesystem. They do not know or care what these bytes represent, or what format they are in.
ContentManager is primarily a deserialization mechanism. It is responsible for taking a sequence of bytes which contains a .xnb file created by the XNA Framework Content Pipeline, and turning those bytes into managed objects. It is also responsible for managing the lifespan of the resulting objects.
By default, ContentManager.OpenStream is wired up to call TitleContainer.OpenStream, because .xnb files are usually deployed as part of the game, so you most often want to load them from the title container. But if you override the OpenStream method, you can make ContentManager read from somewhere else. It could load from isolated storage, or a save game storage container, or a MemoryStream (options that have limited usefulness in practice, because you cannot compile to .xnb format at runtime, so the only way to get .xnb data into isolated storage would be to copy over one that was created at build time, and I can't think of any reason that would ever be useful, but there you go :-)
In the same way that ContentManager can deserialize from anywhere that provides a stream, you can also use any other deserialization mechanism to interpret the bytes obtained from any of these sources. If your title container contains files that are not in .xnb format, you could process them using BinaryReader, or XmlSerializer, or Texture2D.FromStream, or whatever else makes sense for the format of that particular data.