很多测试数据存储在大型文本文件(如 CSV)中。考虑采样率为 1kHz 的情况,持续采集几分钟就能产生百万行数据文件。
本文考虑 csv 文件,其特征在于:
- 具有标题行,有的场景下标题行数目不固定
- 每行数据列数固定,分隔符固定(比如逗号或分号)
本文介绍提升 MATLAB 读取大型文本数据文件性能的方法。
读取大文件:使用 textscan 替代 readtable
考虑如下 csv 文件:
| |
初始代码使用 readtable 读取数据:
| |
历时 1.919952 秒。
textscan 是底层 C 实现,比 readtable 快 2-3倍。
| |
历时 0.650829 秒。(用时减少 66%) 历时 0.168380 秒。(考虑数据解析的总用时减少 57%)
优化文件打开参数
数据基本上只由 ASCII 字符组成(数字、逗号、换行等),我们可以优化 fopen 的参数,这里显式指定机器格式为 'native',避免做不必要的字节序转换;同时将字符编码固定为 US-ASCII,跳过自动编码检测,从而进一步提升性能:
| |
| 编码方案 | 耗时 | 相对性能 |
|---|---|---|
| 不指定(自动检测) | ~1.0s | 基准 |
| GB18030 | 0.75s | +25% |
| UTF-8 | 0.70s | +30% |
| US-ASCII | 0.65s | +35% ⭐ |
处理变长标题行
有时标题行位置不固定,比如随测量通道数变化:
| |
这时我们当然希望能动态定位标题行,而不是手动数行。注意到“真正的”标题行是:
| |
容易想到的做法是逐行读取,直到找到该行:
| |
Found header line. 历时 0.786832 秒。
更快的方法是使用 fread 一次性读取整个文件内容,然后使用 strfind 在内存中搜索标题行:
| |
历时 0.052721 秒。
其他
如果数据中包含空数据(即连续分隔符),需要在
textscan中指定'EmptyValue', NaN以正确处理。如果可能重复读取同一文件,考虑将数据缓存到 MAT 文件中以加快后续读取速度。
1 2 3 4 5 6 7 8 9 10[fileDir, fileBase] = fileparts(filePath); matPath = fullfile(fileDir, [fileBase '.mat']); if exist(matPath, 'file') cache = load(matPath, 'data', 'vars'); data = cache.data; vars = cache.vars; else [data, vars] = loaderFunc(filePath); save(matPath, 'data', 'vars'); end