Skip to content

The virtual file system

jpastuszek edited this page Oct 21, 2010 · 2 revisions

Files and Streams

There are two different levels of API to access files and folders in NUI. The low level approach consists of creating an instance of the right class for the type of data you want to access (file, network resource, some memory chunk, native resources contained in you executable, the contents of a zip file, etc.).

Imagine you are creating a text editor. One of the task you need to implement is the loading of the text from a file. One of the ways of doing this would be to create an nglFile directly and read the data from the file. However this really is suboptimal as it would lock your classes in using only one type of data source: a file. As soon as you will need to read from anything else like a resource or the network you would have to write some more code and make it much more complex to create special cases for each data source you would like to support.

NUI as a higher level API to access data sources and destinations: nglStream. There are 3 kinds of stream interfaces: A stream can be a source (nglIStream), a destination (nglOStream) or both (nglIOStream). As those really are just a set of interfaces you can plug any kind of data providers and consumers on top of them: files, native resources, memory, zip files, network streams, etc. One good example of this is nglImage. The nglImage class can create textures from many different sources but the most commonly used one probably is nglImage(nglIStream* pInput, nglImageCodec* pCodec = NULL); This constructor tries to load an image file from the given stream (it can even try to detect the actual codec to load the image if none is explicitely given). This means that with this constructor one can directly create an image from any data source without the need to code special cases for each source.

You can have a look at the classes that inherit from nglIStream, nglOStream and nglIOStream in the documentation to learn about all the implementations and special cases that have already been done for you. This is all well and good but you may think that this solves only one half of the problem: you still need to explicitely create the right data source depending on your need, for example you may have to create an nglIFile and an nglNativeResource explicitely in order to create the correct kind of stream for you data. This will still make your data handling cumbersome. Unless you use nglPath and the NUI Virtual File System for you to solve most of those problems.

nglPath

nglPath is a very useful class that helps solve most file path handling problems:

  • get path infos: Is a path a leaf or a folder? Does the path exists? What is its size? etc.
  • create folders. It can also handle recursive folder creation.
  • path string handling: concatenate pathes, get the nodename or the parent part of a path, as well as the extension, or even change the extension, etc.
  • and, last but not least: nglStream creation!

There are two methods from nglPath that are particularly handy: OpenRead and OpenWrite. OpenRead tries to create an nglIStream from a given path while OpenWrite tries to create an nglIOStream. If you don’t do anything special in your program nglPath will only be able to create streams from basic files, just like nglFile and nglIFile/nglOFile/nglIOFile would. But there is a way to tell nglPath about new kinds of files that are not really related to your hard-disk: nglVolume!

nglVolume

nglPath’s real job is to handle the Virtual File System. The basic File System can access basic volumes (for example your hard drives or your dvd-rom reader). But we can create an nglVolume that presents some data source just like if it was located on a hard drive or a cdrom. Once more, the basic example is that we can present all the resources in your executable as a special volume of files: nuiNativeResourceVolume does exactely that. It inherits from nglVolume and implements everything needed in order to handle native resources ust like a bunch of folders. This is so handy that we decided to mount that volume directly from the start so that one can access the executable resources from a standard path: “rsrc:/”. This is a read only path but it permits you to load images, text files, sounds or whatever you stored in your resource exactely in the same way you would a simple file on your hard drive. Just create a stream from the right nglPath and you’re set:

nglPath path(_T("rsrc:/SomeFolder/SomeFilePath"));
nglIStream* pStream = path.OpenRead();

if (!pStream)
{
  // Do some error handling here as there was a problem creating a stream from the given path
}
else
{
  // do something with the stream. get its size, read some data, etc.
}
delete pStream;

This simple piece of code is ready to handle any file from the virtual file system. And you can very easily create some new kind of volumes needed by you applications. For example you may have to deal with big files containing many kinds of data for a video game, or zip files, or even some encrypted data that you want to access directly and decrypt on the fly.. nglVolume is ready to serve you. You can even create a direct access to some particular part of your hard drive by creating an nglNativeVolume that points to a restricted part of your real file system directly from the simplicity of a very usual path.