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,Eraseover any storage that exposes aIStorageControllerProvider. See Tiny File System below.
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 cards —
StorageController.FromName(SC20100.StorageController.SdCard). See SD Cards for the full reference. SPI-attached SD cards are also supported via theManagedFileSystemdriver. - 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.
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
| Namespace | Description |
|---|---|
| GHIElectronics.TinyCLR.Devices.Storage | Storage controller for mounting file systems |
| GHIElectronics.TinyCLR.IO | File system I/O classes |
| GHIElectronics.TinyCLR.IO.TinyFileSystem | Lightweight file system for NOR flash |