Main Content

Generate Code That Reads Data from a File

This example shows how to generate C code from a MATLAB® function that reads data from a file.

Inspect Data File

In this example, you generate code to read mydata.csv, a file in comma-separated values (CSV) format. This file contains measurements of the temperature of a furnace (in degrees Celsius) at various times over the course of several days. The file contains several lines of description followed the data in CSV format.

type mydata.csv
Temperature of a furnace in degrees Celsius
measured at various times over a course of 
one week
time, temp
19-Aug-2021 10:32:35, 81
20-Aug-2021 10:40:28, 72
22-Aug-2021 10:19:36, 98
23-Aug-2021 11:00:02, 70
24-Aug-2021 10:54:27, 90
25-Aug-2021 11:03:00, 87

Create and Test Entry-Point Function

Create a MATLAB function my_readtable to read the data file mydata.csv. The function ignores the initial description lines and creates a MATLAB table containing datetime and numeric values. Because the MATLAB function readtable is not supported for code generation, the my_readtable function uses low-level file I/O functions like fopen, fgetl, fscanf, feof, and fclose to open, read, and close the file.

type my_readtable.m
function T = my_readtable(filename,numRecords) %#codegen

f = fopen(filename,"r");

% Scan and ignore a variable number of description lines at the beginning
% of the CSV file.
line = fgetl(f);
coder.varsize("line");
while(~ismember(',',line))
    line = fgetl(f);
end

% Table variable names.
names = {'time' 'temp'};

% Initialize variables. Define 'months' cell array that is used to convert
% name of month to serial number of month in the next code block.
i = 1;
months = {'Jan' 'Feb' 'Mar' 'Apr' 'May' 'Jun' 'Jul' 'Aug' 'Sep' 'Oct' 'Nov' 'Dec'};

dateAndTime = repmat(datetime,1,numRecords);
temperature = zeros(1,numRecords);

% Read each line in the CSV file till you reach EOF. Construct an array of
% datetime and double values (for time and temp columns).
while(~feof(f))
    day = fscanf(f,'%u-');
    month_name = string(fscanf(f,'%3c',1));
    month_number = find(month_name == months);
    [result,count] = fscanf(f,'-%u %u:%u:%u, %u');

    % Check that the last fscanf call read all remaining data in the line
    assert(count == 5) 

    year = result(1);
    hour = result(2);
    minute = result(3);
    second = result(4);
    dateAndTime(i) = datetime(year,month_number,day,hour,minute,second);
    temperature(i) = result(5);
    i = i + 1;
end

% Construct the table from the values read in the previous code block.
T = table(dateAndTime',temperature','VariableNames',names);
fclose(f);

end

This entry-point function (top-level MATLAB function for which you generate code) uses these coding patterns that make it suitable for code generation:

  • The size of the character vector line changes as the function reads each line of the initial description. The coder.varsize directive instructs the code generator to produce code that dynamically allocates memory for the variable line.

  • The function hardcodes the column header names 'time' and 'temp' instead of reading them from the CSV file at run time. This is because code generation requires table variable names to be compile-time constants.

  • The variable months is defined as a character array instead of a string array because code generation does not support string arrays.

  • The function preinitializes the arrays dateAndTime and temperature before populating them with actual data (in the while loop).

Run the MATLAB entry-point function.

T_matlab = my_readtable("mydata.csv",6)
T_matlab=6×2 table
            time            temp
    ____________________    ____

    19-Aug-2021 10:32:35     81 
    20-Aug-2021 10:40:28     72 
    22-Aug-2021 10:19:36     98 
    23-Aug-2021 11:00:02     70 
    24-Aug-2021 10:54:27     90 
    25-Aug-2021 11:03:00     87 

Use MEX Function to Test Generated Code

To test the output of code generation inside the MATLAB environment, generate and run a MEX (MATLAB executable) function. A MEX function is a compiled C/C++ function that runs in the MATLAB environment. Use the codegen command to generate a MEX function at the command line.

In the codegen command, specify the following data types for the input arguments to the function my_readtable:

  • filename is an unbounded variable-length string

  • numRecords is a double scalar

s = "mystring";
t = coder.typeof(s);
t.Properties.Value = coder.typeof('a',[1 inf]);

codegen my_readtable -args {t,0} -report
Code generation successful: To view the report, open('codegen/mex/my_readtable/html/report.mldatx')

The code generator produces the MEX function my_readtable_mex. Run the generated MEX function using the same value you used to test the MATLAB function.

T_mex = my_readtable_mex("mydata.csv",6)
T_mex=6×2 table
            time            temp
    ____________________    ____

    19-Aug-2021 10:32:35     81 
    20-Aug-2021 10:40:28     72 
    22-Aug-2021 10:19:36     98 
    23-Aug-2021 11:00:02     70 
    24-Aug-2021 10:54:27     90 
    25-Aug-2021 11:03:00     87 

Generate Standalone C Code

Use the codegen command to generate a static C library for my_readtable. The generated library can be deployed on the target hardware.

codegen -config:lib my_readtable -args {t,0} -report
Code generation successful: To view the report, open('codegen/lib/my_readtable/html/report.mldatx')

The file I/O functions are implemented differently between the MEX function and the standalone code. For example, during MEX code generation, the code generator automatically treats fscanf as an extrinsic function. This means that the generated MEX function dispatches the fscanf calls to the MATLAB engine for execution. In contrast, when you generate standalone code, the code generator generates C/C++ code for the body of the fscanf function.

If you generate a MEX function but want to generate C/C++ code for extrinsic functions, disable extrinsic function calls by setting the ExtrinsicCalls property of the coder.MexCodeConfig object to false. Alternatively, in the MATLAB Coder app, on the More Settings tab, set Keep extrinsic calls to No.

If you have Embedded Coder®, you can verify the generated standalone code by using Software-In-the-Loop (SIL) or Processor-In-the-Loop (PIL) execution before deployment. See SIL and PIL Verification for Deployment on Raspberry Pi (Embedded Coder).

See Also

| | | |

Related Examples

More About