File I/O and MEX
MATLAB provides a layered I/O API: a high-level family — readtable, readmatrix, load, imread — that infers format and shape from the file; a file-store family — datastore, tall — that processes data too large to load at once; and a low-level C-style family — fopen, fread, fprintf — for byte-oriented or position-controlled access. Beyond plain I/O, the MEX interface compiles C, C++, or Fortran code into shared libraries callable from MATLAB; MATLAB Coder compiles MATLAB code into C; the Engine APIs embed MATLAB in C, C++, Java, .NET, and Python applications. This page covers the I/O primitives and the principal external interfaces.
High-level table I/O
The most-used file functions in modern MATLAB read and write tables:
T = readtable("data.csv");
writetable(T, "out.csv");
T = readtable("data.xlsx", 'Sheet', "Sheet2");
writetable(T, "out.xlsx", 'Sheet', "Results");
The reader infers column types from the data; for finer control, the import options object configures every aspect:
opts = detectImportOptions("data.csv");
opts.VariableTypes(2) = "string";
opts.MissingRule = "fill";
opts.FillValue = -1;
T = readtable("data.csv", opts);
For the numeric-only case, readmatrix and writematrix skip the column-naming machinery and return a plain numeric array:
A = readmatrix("data.csv");
writematrix(A, "out.csv");
MAT-files
The native MATLAB binary format is the MAT-file (.mat). It stores arbitrary MATLAB values with their full type information and is the canonical format for persisting workspaces and intermediate results:
x = rand(1000);
y = "hello";
z = struct('a', 1, 'b', 2);
save("workspace.mat") % saves all workspace variables
save("subset.mat", 'x', 'y') % saves only x and y
save("v7.mat", 'x', '-v7.3') % version 7.3 (HDF5-based, large files)
clear
load("workspace.mat") % restores x, y, z
data = load("workspace.mat"); % loads into a struct
The -v7.3 flag selects the HDF5-based variant that supports arrays larger than 2 GB and that other tools can read with an HDF5 library. The default (v7) is faster for typical files but is limited to 2 GB per variable.
Low-level file I/O
For binary files, position-controlled reads, or byte-level work, the C-style API is the right choice:
fid = fopen("binary.dat", "rb");
if fid < 0
error("Could not open file")
end
cleanup = onCleanup(@() fclose(fid));
n = fread(fid, 1, "int32");
data = fread(fid, n, "double");
status = fseek(fid, 0, 'eof');
sz = ftell(fid);
The conventional pairs are fopen/fclose, fread/fwrite, fprintf/fscanf, fseek/ftell. The 'r'/'w'/'a' modes correspond to the C versions; 'b' requests binary mode (no newline translation on Windows). Every fopen should be paired with a guaranteed fclose; the onCleanup idiom (covered in Error handling) is the recommended form.
The fprintf and fscanf accept the standard C format specifiers; for arrays, fwrite(fid, A, "double") writes the matrix in column-major order.
Text files line-by-line
For free-form text — log files, scientific data files with mixed structure — the conventional pattern uses fopen and fgetl:
fid = fopen("log.txt", "rt");
cleanup = onCleanup(@() fclose(fid));
while ~feof(fid)
line = fgetl(fid);
if isempty(line)
continue
end
if startsWith(line, "ERROR")
disp(line)
end
end
The functions fgetl (returns char), fgets (returns char with newline), and readlines (R2020b+, returns a string array of all lines at once) cover the principal modes.
Datastores and tall arrays
For files that are too large to load into memory, the datastore abstraction reads on demand:
ds = datastore("logs/*.csv");
ds.SelectedVariableNames = ["timestamp", "level", "message"];
while hasdata(ds)
chunk = read(ds);
process(chunk);
end
A tall array wraps a datastore and supports lazy, vectorised operations that the runtime executes only when gather is called:
T = tall(datastore("logs/*.csv"));
errors = T(T.level == "ERROR", :);
count = gather(height(errors)); % executes the deferred pipeline
Tall arrays integrate with the Parallel Computing Toolbox: a tall pipeline transparently dispatches to a parallel pool when one is available, and to a Spark cluster when MATLAB Parallel Server is configured for one.
Images, audio, video
img = imread("photo.png"); % uint8 RGB array
imwrite(img, "out.jpg", 'Quality', 80);
[y, fs] = audioread("song.wav");
audiowrite("out.flac", y, fs);
v = VideoReader("movie.mp4");
while hasFrame(v)
frame = readFrame(v);
process(frame);
end
The image, audio, and video APIs handle most common formats out of the box. Toolbox-specific formats (DICOM, FITS, scientific microscopy formats) are supported through the Image Processing Toolbox.
Web and network I/O
% HTTP GET
data = webread("https://api.example.com/values");
% HTTP POST with options
opts = weboptions('MediaType', 'application/json', 'Timeout', 10);
response = webwrite("https://api.example.com/post", struct('x', 1, 'y', 2), opts);
% TCP / UDP
t = tcpclient("localhost", 8080);
write(t, [1 2 3], "uint8")
data = read(t, 10, "uint8");
The webread/webwrite family handles HTTP with JSON, XML, or arbitrary body content. The tcpclient/tcpserver and udpport classes (in the Instrument Control Toolbox for some configurations, in base MATLAB for others) handle byte-stream sockets.
JSON
s = jsondecode('{"name": "Ada", "year": 1815}');
% s.name = "Ada"; s.year = 1815
txt = jsonencode(s);
% '{"name":"Ada","year":1815}'
txt = jsonencode(s, "PrettyPrint", true);
The functions are bidirectional and handle the conventional mapping (object → struct, array → cell or numeric array, null → empty). The R2021b form 'PrettyPrint', true produces indented output.
MEX — the C interface
A MEX file is a dynamically linked library written in C, C++, or Fortran that exposes a function callable from MATLAB. The mechanism has been the canonical way to extend MATLAB with performance-critical code since the 1980s.
A minimal C MEX file:
#include "mex.h"
void mexFunction(int nlhs, mxArray *plhs[],
int nrhs, const mxArray *prhs[])
{
if (nrhs != 1) mexErrMsgIdAndTxt("doubleIt:nargin", "Expected 1 arg");
double *x = mxGetDoubles(prhs[0]);
mwSize n = mxGetNumberOfElements(prhs[0]);
plhs[0] = mxCreateDoubleMatrix(1, n, mxREAL);
double *y = mxGetDoubles(plhs[0]);
for (mwSize i = 0; i < n; i++) y[i] = 2.0 * x[i];
}
Compile from inside MATLAB:
mex doubleIt.c
doubleIt([1 2 3]) % [2 4 6]
The MEX API exposes MATLAB arrays as mxArray* pointers; the mx* accessor family — mxGetDoubles, mxGetData, mxGetM, mxGetN, mxCreateDoubleMatrix, mxIsClass — provides typed read and construction. The C++ MEX interface (R2018a+) wraps these in modern C++ classes with matlab::mex::Function as the entry point and matlab::data::Array as the array type; it is the recommended interface for new MEX code.
MEX is used when:
- A specific algorithm cannot be vectorised efficiently in MATLAB and the inner loop is the bottleneck.
- An existing C/C++/Fortran library must be called from MATLAB.
- Hardware access (serial ports, custom drivers) requires a C interface.
MATLAB Coder
MATLAB Coder generates portable C and C++ source code from a subset of MATLAB. The mechanism is the right choice for deploying MATLAB algorithms to embedded systems, microcontrollers, or as a library callable from other applications. The supported subset excludes some dynamic features (struct field addition, dynamic class loading, full string-class methods) but covers the majority of numerical code:
% A function suitable for codegen
function y = process(x) %#codegen
y = x.^2 + 1;
end
codegen process -args {coder.typeof(double(0), [Inf 1])}
% Generates process.c, process.h, and a static library
The %#codegen pragma signals that the function is intended for code generation; the MATLAB Coder app provides an interactive workflow for converting whole projects.
Engine APIs
The Engine APIs allow other applications to call MATLAB:
- C Engine —
engOpen,engEvalString,engGetVariable. The legacy API. - C++ Engine (R2017b+) —
matlab::engine::startMATLAB, modern C++ types. - Python Engine —
import matlab.engine; eng = matlab.engine.start_matlab(); eng.someFunc(...). - Java Engine — similar, for Java applications.
- .NET Engine — for C# applications.
The Python case is the most common: many users embed MATLAB into a primarily-Python workflow to call a single MATLAB function or to use a specific toolbox.
import matlab.engine
eng = matlab.engine.start_matlab()
A = matlab.double([[1, 2], [3, 4]])
b = matlab.double([[5], [6]])
x = eng.mldivide(A, b)
print(x)
eng.quit()
The mechanism is bidirectional: from MATLAB, pyrun("...") and py.module.function(...) call Python.
A note on text encoding
By default MATLAB reads and writes text files in the system encoding — UTF-8 on macOS and Linux, the platform’s ANSI code page on Windows. To force UTF-8 on Windows:
fid = fopen("data.txt", "wt", 'n', 'UTF-8');
The 'n' (native byte order) and 'UTF-8' encoding pair tells MATLAB to write a UTF-8 file regardless of the system setting. The convention is increasingly important as cross-platform reproducibility becomes the norm; new code should explicitly set the encoding when portability matters.