Float Binary Table (FBT) is a minimal binary table format for float-only datasets. It stores a small header with feature names followed by rows of little-endian float32 values. The format is designed to be straightforward to read and write and is much simpler than parquet and similar formats.
FBT is useful when you want a compact, fast, and predictable layout for ML features or other numeric data, without the overhead of schema evolution, encoding strategies, or nested structures.
All values are little-endian.
Header:
- int32 magic (4 ASCII chars)
- int32 version (1)
- int32 columnCount
- int32 recordSizeBytes (4 * columnCount)
- column names: columnCount * 30 bytes (ASCII, 0-padded)
Body:
- records: row-major float32 values, each row is columnCount floats
The magic field is a 4-byte ASCII signature written at the start of the file. It helps you confirm that you are reading the expected file type and that the header layout matches your reader. Use a stable value (for example FBT1) and pass it as magicExpected when reading.
import tiksem.fbt.FloatBinaryTable
import tiksem.fbt.FloatBinaryTableWriter
val features = listOf("x", "y", "z")
// Write
FloatBinaryTableWriter("/tmp/data.fbt", "FBT1", features).use { w ->
w.appendRow(floatArrayOf(1.0f, 2.0f, 3.0f))
w.appendRow(floatArrayOf(4.0f, 5.0f, 6.0f))
}
// Read
val table = FloatBinaryTable.readFromFile("/tmp/data.fbt", "FBT1")
val row0 = table.getRow(0)
val value = table.getFeature(1, "y")FloatBinaryTable(featureNames: List<String>, data: Array<FloatArray>)- Builds a table from rows. Each row length must equal the feature count.
FloatBinaryTable(featureNames: List<String>, data: FloatArray)- Builds a table from packed row-major data.
getRow(rowNumber: Int): FloatArray- Returns a copy of a row.
getFeature(rowNumber: Int, columnNumber: Int): Float- Returns a value by row and column index.
getFeature(rowNumber: Int, featureName: String): Float- Returns a value by row and feature name.
asList(): List<Map<String, Float>>- Returns a row projection backed by the original data.
writeToFile(file: File, magic: String)- Writes the table to a file with the given 4-byte magic.
writeToFile(outputPath: String, magic: String)- Writes the table to a file path with the given 4-byte magic.
writeToStream(stream: OutputStream, magic: String)- Writes the table to a stream with the given 4-byte magic.
readFromFile(file: File, magicExpected: String? = null)- Reads a table from a file and optionally checks magic. (Companion object)
readFromFile(filePath: String, magicExpected: String? = null)- Reads a table from a file path and optionally checks magic. (Companion object)
readFromStream(inputStream: InputStream, magicExpected: String? = null)- Reads a table from a stream and optionally checks magic. (Companion object)
FloatBinaryTableWriter(outputPath: String, magic: String, featureNames: List<String>)FloatBinaryTableWriter(file: File, magic: String, featureNames: List<String>)FloatBinaryTableWriter(stream: OutputStream, magic: String, featureNames: List<String>)- Creates a streaming writer and writes the header immediately.
appendRow(row: FloatArray)- Appends one row.
flush()- Forces buffered data to the stream.
close()- Flushes remaining data and closes the stream.
- Feature names must be ASCII and are limited to 30 bytes each.
- The format is float32-only.
- The API is in-memory and optimized for simple ML pipelines and feature tables.