Skip to main content

File System

TinyCLR's file-system support is a subset of the full .NET file system API. Most desktop .NET file-system code ports across with minor changes. The built-in driver implements FAT16 and FAT32 with no limitations beyond the FAT spec itself.

TinyCLR provides two file-system paths:

  • FAT — the standard file system used by SD cards, USB drives, and anything else you might want a PC to read. Lives on a StorageController (SD card, USB host, etc.).
  • Tiny File System (TFS) — a lightweight file system designed for raw memory storage like QSPI flash. Implements Open, Read, Write, Erase over any storage that exposes a IStorageControllerProvider. See Tiny File System below.
note

Removable media (USB drives, SD cards) must be partitioned with an MBR record, not GPT. Only FAT16 and FAT32 are supported — not exFAT, NTFS, or ext.

FAT file system

NuGet packages: GHIElectronics.TinyCLR.IO and GHIElectronics.TinyCLR.Devices.Storage.

The same FAT driver works across storage backends — you just pick the right StorageController:

  • SD/MMC cardsStorageController.FromName(SC20100.StorageController.SdCard). See SD Cards for the full reference. SPI-attached SD cards are also supported via the ManagedFileSystem driver.
  • USB Mass Storage — for USB sticks and external drives via USB Host. See USB Host.

Reading and writing files

using System;
using System.Diagnostics;
using System.IO;
using System.Text;
using GHIElectronics.TinyCLR.Devices.Storage;
using GHIElectronics.TinyCLR.IO;
using GHIElectronics.TinyCLR.Pins;

var sd = StorageController.FromName(FEZBit.StorageController.SdCard);
var drive = FileSystem.Mount(sd.Hdc);

// List files in the root directory.
var directory = new DirectoryInfo(drive.Name);
foreach (var f in directory.GetFiles()){
Debug.WriteLine(f.Name);
}

// Append the current UTC timestamp to a text file.
var file = new FileStream(drive.Name + "Test.txt", FileMode.OpenOrCreate);
var bytes = Encoding.UTF8.GetBytes(DateTime.UtcNow.ToString() + Environment.NewLine);
file.Write(bytes, 0, bytes.Length);
file.Flush();

FileSystem.Flush(sd.Hdc);

Low-level access

If you need to bypass the file system and read or write storage sectors directly — for example, to implement a custom file system or read raw partition data — use the controller's Provider property.

warning

Direct provider access bypasses any file system sitting on the storage. Writing through the provider can corrupt the FAT structure if a file system is mounted. Use only when you know what you're doing.

var controller = StorageController.FromName(FEZBit.StorageController.SdCard);

controller.Provider.Open();
controller.Provider.Read(address, count, buffer, 0, TimeSpan.FromSeconds(5));
controller.Provider.Close();

Tiny File System

NuGet package: GHIElectronics.TinyCLR.IO.TinyFileSystem.

Tiny File System (TFS) is a lightweight file system that runs on any memory backend exposing the IStorageControllerProvider interface — typically external QSPI flash, but anything with Read, Write, and Erase operations works.

using System.Diagnostics;
using System.IO;
using GHIElectronics.TinyCLR.IO.TinyFileSystem;

const int CLUSTER_SIZE = 1024;

var tfs = new TinyFileSystem(new QspiMemory(), CLUSTER_SIZE);

if (!tfs.CheckIfFormatted()){
tfs.Format();
}
else{
tfs.Mount();
}

// Write a file.
using (var fsWrite = tfs.Create("settings.dat"))
using (var wr = new StreamWriter(fsWrite)){
wr.WriteLine("This is a TFS test");
wr.Flush();
fsWrite.Flush();
}

// Read it back.
using (var fsRead = tfs.Open("settings.dat", FileMode.Open))
using (var rdr = new StreamReader(fsRead)){
string line;
while ((line = rdr.ReadLine()) != null){
Debug.WriteLine(line);
}
}

Backing TFS with QSPI flash

Below is a minimal IStorageControllerProvider implementation that wraps the on-board QSPI flash. It auto-sizes against whether external deployment is enabled (10 MB available when it is, 16 MB when it isn't) and defaults to 2 MB so that the remaining QSPI can be used by In-Field Update.

using System;
using GHIElectronics.TinyCLR.Devices.Storage;
using GHIElectronics.TinyCLR.Devices.Storage.Provider;
using GHIElectronics.TinyCLR.Native;
using GHIElectronics.TinyCLR.Pins;

public sealed class QspiMemory : IStorageControllerProvider{
public StorageDescriptor Descriptor => this.descriptor;

const int SectorSize = 4 * 1024;

private StorageDescriptor descriptor = new StorageDescriptor(){
CanReadDirect = false,
CanWriteDirect = false,
CanExecuteDirect = false,
EraseBeforeWrite = true,
Removable = true,
RegionsContiguous = true,
RegionsEqualSized = true,
RegionAddresses = new long[] { 0 },
RegionSizes = new int[] { SectorSize },
RegionCount = (2 * 1024 * 1024) / SectorSize,
};

private IStorageControllerProvider qspiDrive;

public QspiMemory() : this(2 * 1024 * 1024) { }

public QspiMemory(uint size){
var maxSize = Flash.IsEnabledExtendDeployment ? (10 * 1024 * 1024) : (16 * 1024 * 1024);

if (size > maxSize)
throw new ArgumentOutOfRangeException("size too large.");
if (size <= SectorSize)
throw new ArgumentOutOfRangeException("size too small.");

if (size != descriptor.RegionCount * SectorSize)
descriptor.RegionCount = (int)(size / SectorSize);

qspiDrive = StorageController.FromName(SC20260.StorageController.QuadSpi).Provider;

this.Open();
}

public void Open() => qspiDrive.Open();
public void Close() => qspiDrive.Close();
public void Dispose() => qspiDrive.Dispose();

public int Erase(long address, int count, TimeSpan timeout)
=> qspiDrive.Erase(address, count, timeout);

public bool IsErased(long address, int count)
=> qspiDrive.IsErased(address, count);

public int Read(long address, int count, byte[] buffer, int offset, TimeSpan timeout)
=> qspiDrive.Read(address, count, buffer, offset, timeout);

public int Write(long address, int count, byte[] buffer, int offset, TimeSpan timeout)
=> qspiDrive.Write(address, count, buffer, offset, timeout);

public void EraseAll(TimeSpan timeout){
for (var sector = 0; sector < this.Descriptor.RegionCount; sector++){
qspiDrive.Erase(sector * this.Descriptor.RegionSizes[0], this.Descriptor.RegionSizes[0], timeout);
}
}
}

API reference

NamespaceDescription
GHIElectronics.TinyCLR.Devices.StorageStorage controller for mounting file systems
GHIElectronics.TinyCLR.IOFile system I/O classes
GHIElectronics.TinyCLR.IO.TinyFileSystemLightweight file system for NOR flash