Files
2026-04-17 14:55:32 -04:00

10 KiB
Raw Permalink Blame History

source_files, generated_at, model, schema_version, sha256
source_files generated_at model schema_version sha256
Common/DTS.Common.Serialization/TDMS/TDMS.File.cs
Common/DTS.Common.Serialization/TDMS/TDMS.File.Writer.cs
2026-04-16T03:37:03.448977+00:00 Qwen/Qwen3-Coder-Next-FP8 1 d8ac04ef5386bd66

TDMS

Documentation: TDMS.File Module


Purpose

This module implements serialization and deserialization logic for the TDMS (Technical Data Management Streaming) file format, a binary format used primarily for storing time-series test data. It defines the DTS.Serialization.TDMS.File class, which represents a TDMS file and encapsulates metadata and configuration (e.g., filtering options, test plan association), and its nested Writer class, responsible for writing Test objects to disk in the NI TDMS v2.0 format (as referenced by the whitepaper URL in comments). The module serves as the core serialization backend for exporting test data in a standardized, interoperable format compatible with National Instruments tools.


Public Interface

Class: DTS.Serialization.TDMS.File

  • Constructor

    public File(Common.ISO.TestPlan plan)
    

    Initializes a new File instance, associating it with a given TestPlan. Calls base("TDMS"), indicating it inherits from Serialization.File.

  • Properties

    • public static string Extension => ".tdms"
      Returns the file extension for TDMS files.
    • public bool UseZeroForUnfiltered { get; set; } = false
      Controls whether unfiltered data should be represented as zero (default: false).
    • public bool FilteredExport { get; set; } = false
      Indicates whether filtered data export is enabled (default: false).
    • public IWriter<Test> Exporter { get; }
      Lazily initializes and returns a Writer instance associated with this File. Sets Writer.TestPlan and Writer.WriterParent appropriately. Throws a wrapped exception on failure.
  • Methods

    • public override void SetEUData(string channelId, FilteredData fd)
      Stores or updates Eu (engineering units) unfiltered data for a given channel ID in an internal dictionary _EUUnfilteredDataForLinearizedChannels.
    • public override FilteredData GetEUData(string channelId)
      Retrieves stored Eu unfiltered data for a given channel ID from _EUUnfilteredDataForLinearizedChannels. Returns null if not present.

Note

: _EUUnfilteredDataForLinearizedChannels is a private Dictionary<string, FilteredData>, used to associate channel IDs with precomputed Eu data (likely for linearized channels).


Nested Class: DTS.Serialization.TDMS.File.Writer

  • Constructor

    internal Writer(File fileType, int encoding)
    

    Internal constructor; initializes the base Writer<File> with the parent File and encoding. The encoding parameter is passed to the base class.

  • Properties

    • public File WriterParent { get; set; }
      Reference back to the parent File instance. Set by File.Exporter getter.
    • public Common.ISO.TestPlan TestPlan { get; set; } = null
      Reference to the test plan associated with the export. Set by File.Exporter.
    • public string ExtensionPrefix { get; set; } = string.Empty
      Optional prefix appended to the base filename (e.g., for multi-file exports).
  • Methods

    • public void Write(string pathname, string id, Test test, bool bFiltering, bool includeGroupNameInISOExport, double minStartTime, int dataCollectionLength)
      Convenience overload of Write(...). Delegates to the 18-parameter overload with many arguments set to null or defaults.
    • public void Write(string pathname, string id, string dataFolder, Test test, bool bFiltering, bool includeGroupNameInISOExport, FilteredData fd, Test.Module.Channel tmChannel, int channelNumber, BeginEventHandler beginEventHandler, CancelEventHandler cancelEventHandler, EndEventHandler endEventHandler, TickEventHandler tickEventHandler, ErrorEventHandler errorEventHandler, CancelRequested cancelRequested, double minStartTime, int dataCollectionLength)
      Main export method. Writes a Test to disk as a .tdms file.
      • Creates the target directory if missing.
      • Constructs filename as Path.Combine(pathname, id + ExtensionPrefix + ".tdms").
      • Writes a binary stream using BinaryWriter.
      • Invokes event handlers (begin, tick, end, error) for progress/error reporting.
      • Calls WriteLeadInAndMetaData(...) and WriteRawData(...) to serialize metadata and raw data.
      • Logs exceptions via APILogger.Log(...).
      • Throws or reports exceptions depending on presence of errorEventHandler.
    • public void Initialize(...)
      Currently empty stub. No-op implementation.

Note

: BeginEventHandler, CancelEventHandler, EndEventHandler, TickEventHandler, ErrorEventHandler, and CancelRequested are delegate/event types used for progress reporting but are not defined in this file.


Invariants

  1. File Format Compliance:

    • The written file adheres to the NI TDMS v2.0 format (per NI whitepaper 3727).
    • The lead-in signature is always "TDSm" (4 bytes).
    • The ToCMask is fixed to 14 (TocMetaData | TocNewObjList | TocRawData).
    • The file version is fixed to 4713.
    • All numeric fields use little-endian encoding (no big-endian support; TocBigEndian bit is unset).
  2. Data Layout:

    • Raw data is stored as 16-bit signed integers (DataTypes.I16), regardless of source data type.
    • Each channels raw data is written sequentially, with no interleaving.
    • The raw data offset and next segment offset are computed and written as 8-byte unsigned integers.
  3. Metadata Structure:

    • Exactly four objects are written:
      1. File object ("/"),
      2. Group object ("/'TestId'"),
      3. One channel object per test.Channels.
    • Group properties are always written in the order defined by GroupProperties enum (TestId, Description, TestDate, TestTime).
    • Channel properties are written in the order defined by ChannelProperties enum.
  4. String Encoding:

    • Strings are written as UTF-16 (via char[]BinaryWriter.Write(char[])), with length prefix (4 bytes).
    • SuperScript characters (e.g., in LinearizationFormula) increase the strings byte length beyond the character count (handled by GetSuperScriptBytes).

Dependencies

  • Internal Dependencies

    • DTS.Serialization.Test (type Test, Test.Module.Channel, Test.Module.AnalogInputChannel, Test.Module)
    • DTS.Serialization.TDMS.FilteredData (used in SetEUData/GetEUData)
    • DTS.Common.ISO.TestPlan (passed to constructor)
    • DTS.Common.Utilities.Logging.APILogger (used for logging exceptions)
  • External Dependencies

    • System.IO (FileStream, BinaryWriter, Directory, Path)
    • System.Linq (used for LINQ queries in GetChannelPropertyLengths)
    • System.Collections.Generic (Dictionary, HashSet, List, Enum.GetValues)
  • Inheritance & Interfaces

    • File inherits from Serialization.File (base class).
    • File implements IWritable<Test>.
    • Writer inherits from Writer<File> (generic base class) and implements IWriter<Test>.

Gotchas

  1. Hardcoded Data Type:
    Raw data is always written as I16 (DataTypes.I16), even if the underlying PersistentChannelInfo[i] values are larger or different types. This may cause data truncation if values exceed Int16 range.

  2. SuperScript Byte Counting Quirk:
    The GetSuperScriptBytes method computes extra bytes for certain Unicode super/subscript characters (e.g., , ², ) in LinearizationFormula. This logic assumes UTF-16 encoding and checks specific byte patterns (byteArray[0], byteArray[1]). This is non-standard and may break if the source strings contain unexpected Unicode.

  3. Unused Parameters in Write(...) Overloads:
    Several parameters in the 18-argument Write(...) overload (dataFolder, fd, tmChannel, channelNumber, minStartTime, dataCollectionLength) are not used in the implementation. Their presence suggests partial refactoring or future extensibility.

  4. Empty Initialize(...) Method:
    The Initialize(...) method is a no-op stub. Its signature implies it may have been intended for streaming or multi-pass writes but is currently unused.

  5. No Support for Event Cancellation:
    Although CancelRequested and CancelEventHandler are passed to Write(...), the method does not check for cancellation during iteration over samples. Progress reporting (tickEventHandler) occurs only once (at 100%) after full write.

  6. String Concatenation in Paths:
    Channel object paths are built via string concatenation (e.g., groupObjectPath + "/" + "'" + channelName + "':" + description + "'"). This assumes no special characters (e.g., quotes, slashes) in channel.ChannelName2 or channel.ChannelDescriptionString, which could break path parsing.

  7. No Validation of Input Data:
    The WriteRawData method writes raw samples directly without validation. If PersistentChannelInfo.NumberOfSamples is inconsistent with actual data length, it may cause IndexOutOfRangeException or silent truncation.

  8. Hardcoded Property Lists:
    Property lists (GroupProperties, ChannelProperties) are fixed via Enum.GetValues. Adding new properties requires updating the enum and all switch statements in WriteGroupProperties and WriteChannelSection.

  9. No Support for Multiple Segments or Append Mode:
    The implementation writes a single segment with fixed nextSegmentOffset = RawDataOffset + totalNumberRawDataBytes. It does not support appending to existing TDMS files or multi-segment files.

  10. Encoding Assumption:
    The encoding parameter passed to Writer constructor is used only in the base class. No explicit encoding configuration (e.g., UTF-8 vs UTF-16) is exposed or validated in this module.


End of Documentation.