We no longer sell products directly from the GHI Electronics website, click here for more details. Please find a Distributor to complete your online order. If you have any questions regarding this notice please contact us at support@ghielectronics.com.

Accessing Folders and Files

Last modified May 4, 2015

Required

Tutorials:  First NETMF Project

Introduction

The File System features in NETMF are very similar to full .NET. There are no limits on file sizes and counts, beside the limits of the FAT file system itself. NETMF supports FAT16 and FAT32.  

With a few minor changes, NETMF file system access can be tested from within the Microsoft NETMF emulator.Changes include removing any of the GHI library dependencies.

Differences between full .NET and NETMF are primarily the need to mount the media and differences in media names. Media name differences are easily handled by accessing the root directory name at runtime and then using that name. Consequently, most online examples on how to use .NET to access files on PCs can be used by NETMF. In NETMF, other than differences for specific physical characteristics, usage of SD/MMC cards and USB memory devices are identical.

This document splits it's examples into two sets. One, for SD/MMC Card file system access; the other, for USB Mass Storage.  The core file operations, for instance open, read, write, etc. are identical between the two.

Warning

The file system does a lot of data buffering internally to speed up the file access time and to increase the life of the flash media. When you write data to a file,it is often saved somewhere in the internal buffers (rather than immediately being written to the media). To make sure the data is stored on the media, you need to flush the data. Flushing (or closing) a file is the only way to guarantee that the data you are trying to write is on the actual media; in addition to the file data,  there is other  information,such as directory information, that may not be written to the media when the file is flushed. For example, if you delete a file and remove the card from the system, the file is probably not actually erased because the directory structure was not flushed.

Under current versions of .NET Micro Framework, with the Flush method of FileStream, there can be a variable time delay before the buffers are actually written to the media; which reportedly can be as large as a minute (see: https://netmf.codeplex.com/workitem/2149 )​. To guarantee that the file buffers and the meta-data are written to the media you need to flush the volume

Ideally, you would unmount the media before it is removed from the system. This may not be always possible and so a FlushAll will guarantee your data is saved.
 
Tip

The SD/MMC Card  examples shown below require the GHI.Hardware, Microsoft.SPOT.IO, and System.IO assemblies.

Some Microsoft documentation class descriptions, such as for Directory, place the library code in the mscorlib assembly; however, they are found in the System.IO assembly.

SD Card. Show Files in Root Directory

This example assumes the card is already inserted; it lists all files available in the root directory.

Note: SD some SD card sockets/interfaces have an internal switch that closes when a card is inserted or ejected. Utilizing the switch is shown further below.

using System.IO;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using Microsoft.SPOT.IO;

using GHI.IO;
using GHI.IO.Storage;

class Program
{
    public static void Main()
    {
        // ...
        // assume SD Card is inserted
        // Create a new storage device
      	// NETMF only allows one SD card
      	// to be supported at the same time.


        SDCard sd_card = new SDCard();

        // this is a non-blocking call 
        // it fires the RemovableMedia.Insert event after 
        // the mount is finished. 
        sd_card.Mount();

        // for some cases, a simple sleep might suffice
        // This example just waits on the event before proceeding
        // (After first time firing of the event, you may want
        // to disable the handler or re-assign it
        bool fs_ready = false;
        RemovableMedia.Insert += (a, b) =>
        {
            fs_ready = true;
        };
        while (! fs_ready ) {
            System.Threading.Thread.Sleep(50);
        }


        // Assume one storage device is available, access it through 
        // NETMF and display the available files and folders:
        Debug.Print("Getting files and folders:");
        if (VolumeInfo.GetVolumes()[0].IsFormatted)
        {
            string rootDirectory =
                VolumeInfo.GetVolumes()[0].RootDirectory;
            string[] files = Directory.GetFiles(rootDirectory);
            string[] folders = Directory.GetDirectories(rootDirectory);

            Debug.Print("Files available on " + rootDirectory + ":");
            for (int i = 0; i < files.Length; i++)
                Debug.Print(files[i]);

            Debug.Print("Folders available on " + rootDirectory + ":");
            for (int i = 0; i < folders.Length; i++)
                Debug.Print(folders[i]);
        }
        else
        {
            Debug.Print("Storage is not formatted. " +
                "Format on PC with FAT32/FAT16 first!");
        }
        // Unmount when done
        sd_card.Unmount();
    }
}

SD Card. Writing Files

There is more than one way to open files. I will only cover FileStream objects. This example will open a file and write a string to it. Since FileStream will only take byte arrays, we need to convert our string to byte array.

using System.Threading;
using System.Text;
using Microsoft.SPOT;
using System.IO;
using Microsoft.SPOT.IO;
using GHI.IO.Storage;


public class Program
{
    static void Main()
    {
        // if necessary, check that SD is present here...

        SDCard sd_card = new SDCard();

 
        sd_card.Mount();
        bool fs_ready = false;
        RemovableMedia.Insert += (a, b) =>
        {
            fs_ready = true;
        };
        while (! fs_ready ) {
            System.Threading.Thread.Sleep(1);
        }

        // Assume only one storage device is available
      	// and that the media is formatted
        string rootDirectory = VolumeInfo.GetVolumes()[0].RootDirectory;
        FileStream FileHandle = new FileStream(rootDirectory +
                                      @"\hello.txt", FileMode.Create);
        byte[] data =
           Encoding.UTF8.GetBytes("This string will go in the file!");
        FileHandle.Write(data, 0, data.Length);
        FileHandle.Close();

        sd_card.Unmount();



    }
}

SD Card. Reading a File

Take the SD Card used in the last example, put it in a PC and you will see the file.

For this example, we use the same SD Card written to by the last example. The file is opened and read to verify its contents.

using System.Threading;
using System.Text;
using Microsoft.SPOT;
using System.IO;
using Microsoft.SPOT.IO;
using GHI.IO.Storage;


public class Program
{
    static void Main()
    {
        // ... If desired, check if SD is inserted

        // SD Card is inserted
        // Create a new storage device
        SDCard sd_card = new SDCard();

        // Mount the file system
        sd_card.Mount();
        bool fs_ready = false;
        RemovableMedia.Insert += (a, b) =>
        {
            fs_ready = true;
        };
        while (!fs_ready)
        {
            System.Threading.Thread.Sleep(1);
        }


        // Assume one storage device is available, 
        // access it through NETMF
        string rootDirectory = VolumeInfo.GetVolumes()[0].RootDirectory;
        FileStream FileHandle = new FileStream(rootDirectory +
                 @"\hello.txt", FileMode.Open, FileAccess.Read);
        byte[] data = new byte[100];
        int read_count = FileHandle.Read(data, 0, data.Length);
        FileHandle.Close();
        Debug.Print("The size of data read is: " +
                    read_count.ToString());
        Debug.Print("Data from file:");
        Debug.Print(new string(Encoding.UTF8.GetChars(data), 0,
              read_count));

        sd_card.Unmount();

    }
}

SD Card. Media Detection.

Previous examples assumed that the card was already inserted and mostly ignored whether that media was formatted (contained a file system). The following example shows an application without such assumptions; additionally, it demonstrates the Format method.

Together, InsertEventHandler, EjectEventHandler, and IsSDCardPresent are used to manage physical card activities; which, in turn, are used to control mounting (Mount, Unmount) of the card. Once mounted, the file-system can be used.

 

using System;
using System.IO;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.IO;

using GHI.IO.Storage;


public class Program
{
    // evt is used to avoid the possibility that accesses to the 
    // mounted file system do not occur until mount()
    // is fully done.
    private static AutoResetEvent evt = new AutoResetEvent(false);
  
  	//Make sure to set the pin to your sd card detect pin.
  	private static InputPort sdCardDetect = new InputPort(Cpu.Pin.GPIO_NONE, false, Port.ResistorMode.Disabled);
  
    public static void Main()
    {
        RemovableMedia.Insert += new InsertEventHandler(RemovableMedia_Insert);
        RemovableMedia.Eject += new EjectEventHandler(RemovableMedia_Eject);

        // Start auto mounting thread
        new Thread(SDMountThread).Start();
        evt.WaitOne(); // yield here until mounting and initializing is finished

        // Your program goes here
        // ...

    }

    // This event is fired by unmount; not neccesarily by physical ejection of media
    static void RemovableMedia_Eject(object sender, MediaEventArgs e)
    {
        Debug.Print("SD card unmounted, eject event fired");
        // as desired signal other thread(s) in application
        // that unmount occurred
    }

    static void RemovableMedia_Insert(object sender, MediaEventArgs e)
    {
        Debug.Print("Insert event fired; SD card mount is finished.");

        // insert code here for anything the program wants to do immediately
        // after mounting occurs...

        if (e.Volume.IsFormatted)
        {
            Debug.Print("Available folders:");
            string[] strs = Directory.GetDirectories(e.Volume.RootDirectory);
            for (int i = 0; i < strs.Length; i++)
                Debug.Print(strs[i]);

            Debug.Print("Available files:");
            strs = Directory.GetFiles(e.Volume.RootDirectory);
            for (int i = 0; i < strs.Length; i++)
                Debug.Print(strs[i]);
        }
        else
        {
            Debug.Print("SD card is not formatted. Formatting...");

            // VolumeInfo is the class that contains volume information for a specific
            //      media.
            // .GetVolumes()[0] aquires the first volume on the device. Change the 
            //      index for different volumes.
            // .Format("FAT", 0); Selects the "FAT" file system as the format type.
            VolumeInfo.GetVolumes()[0].Format("FAT", 0);
        }
        evt.Set(); // proceed with other processing
    }

    public static void SDMountThread()
    {
        SDCard SD = null;
        const int POLL_TIME = 500; // check every 500 millisecond

        bool sdExists;
        while (true)
        {
            try // If SD card was removed while mounting, it may throw exceptions
            {
                sdExists = sdCardDetect.Read();

                // make sure it is fully inserted and stable
                if (sdExists)
                {
                    Thread.Sleep(50);
                    sdExists = sdCardDetect.Read();
                }

                if (sdExists && SD == null)
                {
                    SD = new SDCard();
                    SD.Mount();
                }
                else if (!sdExists && SD != null)
                {
                    SD.Unmount();
                    SD.Dispose();
                    SD = null;
                }
            }
            catch
            {
                if (SD != null)
                {
                    SD.Dispose();
                    SD = null;
                }
            }

            Thread.Sleep(POLL_TIME);
        }
    }
}

USB Mass Storage Devices

USB mass storage devices, such as memory sticks and card readers are supported on GHI's NETMF devices.

If you compare the following example with those above for SD Cards, you will see how easy it is to program for one, the other, or both with virtually identical code.

using System;
using System.Threading;
using System.IO;
using Microsoft.SPOT;
using System.Text;
using Microsoft.SPOT.IO;
using GHI.Usb;
using GHI.Usb.Host;
using GHI.IO.Storage;



public class Program
{
    // evt is used to avoid the possibility that accesses to the 
    // mounted file system do not occur until mount()
    // is fully done.
    private static AutoResetEvent evt = new AutoResetEvent(false);
    private static MassStorage usb_storage;
    private static string rootDirectory;
    public static void Main()
    {


        RemovableMedia.Insert += new InsertEventHandler(RemovableMedia_Insert);
        RemovableMedia.Eject += new EjectEventHandler(RemovableMedia_Eject);

        // Unlike SD Card detection, the USB Host Controller sends an
        // event when a Mass Storage device is plugged-in.
        Controller.MassStorageConnected += (sender, massStorage) =>
        {
            usb_storage = massStorage;
            usb_storage.Mount();  // fires the insert event when finished
        };
      	Controller.Start();
      
        evt.WaitOne(); // yield here until mounting and initializing is finished

        byte[] data;
        // write
        using (var FileHandle = new FileStream(rootDirectory +
                                      @"\hello.txt", FileMode.Create))
        {
            data =
               Encoding.UTF8.GetBytes("This string will go in the file!");
            FileHandle.Write(data, 0, data.Length);
        }

        // read
        int read_count;
        using (var FileHandle = new FileStream(rootDirectory +
                 @"\hello.txt", FileMode.Open, FileAccess.Read))
        {

            data = new byte[100];
            read_count = FileHandle.Read(data, 0, data.Length);
        }
        Debug.Print("The size of data we read is: " +
                    read_count.ToString());
        Debug.Print("Data from file:");
        Debug.Print(new string(Encoding.UTF8.GetChars(data), 0,
              read_count));

        usb_storage.Unmount();

    }

    // This event is fired by unmount
    static void RemovableMedia_Eject(object sender, MediaEventArgs e)
    {
        Debug.Print("USB unmounted, eject event fired");
    }

    static void RemovableMedia_Insert(object sender, MediaEventArgs e)
    {
        Debug.Print("Insert event fired; USB Storage mount is finished.");
        if (e.Volume.IsFormatted)
        {
            rootDirectory = e.Volume.RootDirectory;

            Debug.Print("Available folders:");
            string[] strs = Directory.GetDirectories(e.Volume.RootDirectory);
            for (int i = 0; i < strs.Length; i++)
                Debug.Print(strs[i]);

            Debug.Print("Available files:");
            strs = Directory.GetFiles(e.Volume.RootDirectory);
            for (int i = 0; i < strs.Length; i++)
                Debug.Print(strs[i]);
        }
        else
        {
            Debug.Print("Media is not formatted. Formatting...");
            e.Volume.Format("FAT", 0);
            rootDirectory = e.Volume.RootDirectory;
        }
        evt.Set(); // proceed with other processing
    }
}
Warning

Media formatted as FAT12 will not work. This shouldn't be an issue since FAT12 is no longer in use.

 

Leave feedback about this document.
Let us know if the information presented here was accurate, helpful and if you have any suggestions.
Leave feedback about this document.
Let us know if the information presented here was accurate, helpful and if you have any suggestions.

* Indicates required fields.
This form is only for feedback not support.
Review our how to find information guide on locating helpful resources.