Skip to content

Read channels

Find the right channel

find_channel(name) returns the first exact name match. Use find_channels(name) when the name may occur in more than one group, or search_channels for substring, wildcard, or regex queries. A channel's identity includes its location in the file; a repeated name alone may not identify the intended series.

Read several channels with signals() when you need them together. It assembles each channel group's records once, rather than repeating the work for each channel.

Keep values and validity aligned

signal.values() returns the channel's own type, including integers, text, and bytes. signal.values_f64() is a convenient numeric projection, but can lose precision for wide integers and cannot represent byte or text channels.

A channel with an invalidation bit still returns all samples. Check validity alongside values so they stay aligned with the time master:

use falcon_mdf::Mf4File;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let file = Mf4File::open("measurement.mf4")?;
    let channel = file.find_channel("VehicleSpeed").ok_or("channel not found")?;
    let signal = file.signal(channel)?;
    let values = signal.values_f64()?;

    match signal.validity() {
        Some(valid) => {
            for (value, ok) in values.iter().zip(&valid) {
                if *ok {
                    println!("{value}");
                }
            }
        }
        None => println!("{} valid samples", values.len()),
    }
    Ok(())
}

Choose an I/O backend

Backend Use when
Mf4File::open The file is complete and stays unchanged while open
Mf4File::open_buffered Another process may update or replace it, or it is on a network share
Mf4File::from_source Bytes come from an object store, an HTTP range source, or another custom source

For large groups, the streamed signals_chunks API reads in bounded windows. The ordinary full-channel API assembles a data group's records before decoding; its peak memory therefore depends on the largest group. See the performance notes.

Handle unsupported layouts

Opening a file does not guarantee every channel can be decoded. Handle Mf4Error::Unsupported when processing files you did not create:

use falcon_mdf::{Mf4Error, Mf4File};

fn main() -> Result<(), Mf4Error> {
    let file = Mf4File::open("measurement.mf4")?;
    for channel in file.channels() {
        match file.signal(channel).and_then(|signal| signal.values()) {
            Ok(values) => println!("{}: {} samples", channel.name, values.len()),
            Err(Mf4Error::Unsupported { feature, .. }) => {
                eprintln!("{}: unsupported: {feature}", channel.name);
            }
            Err(error) => return Err(error),
        }
    }
    Ok(())
}

See limits and errors for the known format boundaries.