Use readmatrix and writematrix when a CSV contains numeric data. Use readtable and writetable when column names or mixed data types are part of the file contract.
| Task | Function | Best fit |
|---|---|---|
| Read numeric data | readmatrix | Numeric rows with a header that can be skipped |
| Read named or mixed columns | readtable | Headers, IDs, dates, or mixed data types |
| Write a numeric array | writematrix | Numeric output and appended batches |
| Write a table | writetable | Output whose variable names should become headers |
| Write mixed values | writecell | A manually assembled header or mixed text and numbers |
| Control a custom text format | fopen | Irregular records, explicit formatting, or encoding control |
| Maintain an older script | csvread, csvwrite | Legacy code that has not moved to the newer functions |
A spreadsheet is efficient for inspecting one file. Repeated test runs need the same missing-data rules, calculations, plots, and output columns every time. MATLAB is a good fit when that work already belongs in an .m analysis that engineers can review and rerun. Python with pandas can build the same pipeline; the practical reason to use MATLAB is continuity with the equations, plots, and scripts the team already maintains.
This guide develops one such pipeline around a synthetic pump-test export. The script preserves an unavailable pressure reading, rejects an unexpected file shape, calculates pressure rise from complete records, and writes a checked output file. The downloadable workspace uses MATLAB-syntax code and was executed with the RunMat runtime.
The pump-test result
The sample represents one short pump run. A test bench records elapsed time, inlet pressure, outlet pressure, and flow every half-second:
elapsed_s,inlet_pressure_kpa,outlet_pressure_kpa,flow_l_min
0.0,101.2,142.1,18.4
0.5,101.3,143.0,18.7
1.0,101.2,144.4,18.9
...
3.0,101.4,NA,19.6
3.5,101.5,149.4,19.7The NA at three seconds is deliberate. Converting it to zero would manufacture a pressure drop. Removing only that outlet-pressure value would shift the remaining measurements out of alignment. The analysis must remove the entire record before calculating pressure rise:
pressure_rise_kpa = outlet_pressure_kpa - inlet_pressure_kpa;The code fragments below develop the same script. Open the complete workspace when you want to run pump_test_analysis.m with pump_test.csv already loaded beside it.
Import the data without hiding the gap
Every populated field below the header should be numeric, so readmatrix is the shortest path. NumHeaderLines skips the column names, while TreatAsMissing converts NA to NaN without changing a measured zero.
This first checkpoint is self-contained. It reads the sample, checks the expected dimensions, and reports the missing outlet-pressure row.
data = readmatrix("pump_test.csv", ...
"NumHeaderLines", 1, ...
"TreatAsMissing", "NA");
if size(data, 2) ~= 4 || size(data, 1) == 0
error("pump_test.csv does not match the expected four-column export");
end
missing_outlet_rows = find(isnan(data(:, 3)));
fprintf("Imported size: %d x %d\n", size(data, 1), size(data, 2));
fprintf("Missing outlet-pressure row: %d\n", missing_outlet_rows);The sample imports as a 13-by-4 matrix, and row 7 contains the missing outlet pressure. The shape check catches added or removed columns before the script assigns engineering meanings to their positions:
elapsed_s = data(:, 1);
inlet_pressure_kpa = data(:, 2);
outlet_pressure_kpa = data(:, 3);
flow_l_min = data(:, 4);A dimension check cannot detect four columns that have been reordered. The named-column alternative later in this guide checks the header when column order is not controlled.
Keep each test record aligned
Time, pressure, and flow belong to the same recorded instant. One logical mask removes an incomplete row from every vector together:
valid = ~isnan(inlet_pressure_kpa) & ...
~isnan(outlet_pressure_kpa) & ...
~isnan(flow_l_min);
if sum(valid) == 0
error("No complete measurement rows were found");
end
valid_elapsed_s = elapsed_s(valid);
valid_inlet_kpa = inlet_pressure_kpa(valid);
valid_outlet_kpa = outlet_pressure_kpa(valid);
valid_flow_l_min = flow_l_min(valid);
pressure_rise_kpa = valid_outlet_kpa - valid_inlet_kpa;The sample retains 12 of 13 rows. Its mean pressure rise is 46.38 kPa, its peak pressure rise is 49.60 kPa, and its mean flow is 19.42 L/min. Those values come from the synthetic records in the downloadable CSV.
Inspect the missing reading and calculated result
The raw outlet-pressure trace breaks where the logger supplied NA. Plotting pressure rise against the filtered timestamps shows only measurements backed by complete records.

figure(1);
plot(elapsed_s, outlet_pressure_kpa, "o-");
xlabel("Elapsed time (s)");
ylabel("Outlet pressure (kPa)");
title("Raw export: one reading is missing");
grid on;
figure(2);
plot(valid_elapsed_s, pressure_rise_kpa, "o-");
xlabel("Elapsed time (s)");
ylabel("Pressure rise (kPa)");
title("Validated rows: pressure rise");
grid on;The gap remains visible in the raw data, while the derived result contains no fabricated zero or misaligned timestamp.
Write a CSV another system can verify
The receiving system needs column names and a stable five-column shape. Write the header once with writecell, then append the validated numeric rows with writematrix:
processed = [valid_elapsed_s, valid_inlet_kpa, valid_outlet_kpa, ...
valid_flow_l_min, pressure_rise_kpa];
header = {"elapsed_s", "inlet_pressure_kpa", "outlet_pressure_kpa", ...
"flow_l_min", "pressure_rise_kpa"};
writecell(header, "pump_test_validated.csv");
writematrix(processed, "pump_test_validated.csv", "WriteMode", "append");
round_trip = readmatrix("pump_test_validated.csv", "NumHeaderLines", 1);
assert(isequal(size(round_trip), [12 5]), ...
"Validated output must contain 12 rows and 5 columns");
assert(max(abs(round_trip(:, 5) - pressure_rise_kpa)) < 1e-10, ...
"Exported pressure rise does not match the calculated values");The reread catches a missing header line, an incomplete append, or an unexpected output shape before another team or automated process consumes the file.
When column names define the contract
Some loggers preserve four columns but reorder them after a firmware or export-preset change. A table retains the header, allowing the script to reject renamed or reordered variables before calculation.
test = readtable("pump_test.csv", "TreatAsMissing", "NA");
required = ["elapsed_s", "inlet_pressure_kpa", ...
"outlet_pressure_kpa", "flow_l_min"];
if ~isequal(string(test.Properties.VariableNames), required)
error("pump_test.csv has unexpected or reordered columns");
end
test = rmmissing(test);
test.pressure_rise_kpa = test.outlet_pressure_kpa - ...
test.inlet_pressure_kpa;
writetable(test, "pump_test_validated.csv");
fprintf("Validated table rows: %d\n", height(test));rmmissing removes a table row when any variable is missing. writetable carries the verified variable names into the output. Keep the matrix workflow for controlled numeric exports; choose the table workflow when headers, dates, IDs, or mixed types belong to the file contract.
Run the established analysis on Linux
Once the file checks and calculations are fixed in one script, the same entrypoint can run on a Linux processing machine through the RunMat CLI:
runmat pump_test_analysis.mKeep pump_test.csv beside the script or pass an explicit path in your own version. The CLI reference covers headless execution and runtime options. For recorded data that continues into frequency analysis, the MATLAB FFT guide follows a sensor CSV through spectral checks.
Other CSV layouts
Vendor exports may use different delimiters, regional number formats, append-only records, or custom text layouts. Start with the function that matches the file contract, then validate the assumptions your calculation depends on.
| What is different | Better starting point | What to check |
|---|---|---|
| Headers, IDs, dates, or mixed values matter | readtable, then writetable | Required variable names, inferred types, and missing rows |
| Fields use tabs, semicolons, or regional formats | readmatrix with delimiter and separator options | Delimiter, decimal separator, and thousands separator |
| New rows must be added to an existing file | writematrix or writecell with "WriteMode", "append" | Existing column order and whether the header already exists |
| Records have a custom text layout | fopen with textscan or fprintf | Failed opens, encoding, format strings, and fclose |
An older script uses csvread or csvwrite | readmatrix or writematrix | Zero-based offsets, selected ranges, and empty-field behavior |
Frequently asked questions
How do I read a CSV file with headers in MATLAB?⌄
Choose readtable when the column names matter. Choose readmatrix with "NumHeaderLines", 1 when the header can be skipped and the remaining fields are numeric.
Should I use readmatrix or readtable?⌄
readmatrix returns a numeric array that is convenient for matrix calculations. readtable preserves names and mixed types, allowing the script to validate the header before using the columns.
How do I write a CSV file in MATLAB?⌄
Use writematrix for a numeric array, writetable when variable names should become headers, or writecell for manually assembled mixed output.
How do I append rows to a CSV file?⌄
Pass "WriteMode", "append" to writematrix or writecell. Confirm that the header already exists and every appended batch uses the same column order.