受@Axon 回答的启发,我实现了一个“快速”C 程序将文件转换为二进制文件,然后使用 Matlab 的fread
函数将其读取。剧透警告:阅读速度提高了 20 倍……尽管初始转换需要一点时间。
为了使 Matlab 中的工作更容易,文件大小更小,我将每个数字字段转换为一个int16
(短整数)。对于第一个字段 - 看起来像一个 yyyymmdd 字段 - 这涉及拆分为两个较小的数字;同样,十进制数字被转换为两个短整数(鉴于我认为有效的明显范围)。所有这一切都是在认识到“要真正优化,您必须真正了解您的问题”——因此,如果假设无效,结果也会如此。
这是C代码:
#include <stdio.h>
int main(){
FILE *fp, *fo;
long int ld1;
int d2, d3, d4, d5, d6, d7;
short int buf[9];
char c8;
int n;
short int year, monthday;
fp = fopen("bigdata.txt", "r");
fo = fopen("bigdata.bin", "wb");
if (fp == NULL || fo == NULL) {
printf("unable to open file\n");
return 1;
}
while(!feof(fp)) {
n = fscanf(fp, "%ld %d:%d.%d %d.%d %d %c\n", \
&ld1, &d2, &d3, &d4, &d5, &d6, &d7, &c8);
year = d1 / 10000;
monthday = d1 - 10000 * year;
// move everything into buffer for single call to fwrite:
buf[0] = year;
buf[1] = monthday;
buf[2] = d2;
buf[3] = d3;
buf[4] = d4;
buf[5] = d5;
buf[6] = d6;
buf[7] = d7;
buf[8] = c8;
fwrite(buf, sizeof(short int), 9, fo);
}
fclose(fp);
fclose(fo);
return 0;
}
生成的文件大约是原始文件大小的一半——这是令人鼓舞的,并且会加快访问速度。请注意,如果可以将输出文件写入与输入文件不同的磁盘,那将是一个好主意——它确实有助于保持数据流,而不会在查找操作上浪费大量时间。
基准测试:使用 2 M 行的文件作为输入,运行时间约为 2 秒(相同的磁盘)。生成的二进制文件在 Matlab 中读取,内容如下:
tic
fid = fopen('bigdata.bin');
d = fread(fid, 'int16');
d = reshape(d, 9, []);
toc
当然,现在如果要将数字恢复为浮点数,则需要做一些工作;但我认为这是值得的。您必须解决的一个可能问题是小数点后的值具有不同位数的情况:当 b > 100 时,将 (a,b) 转换为浮点数并不像“a + b/100”那么简单...“为学生锻炼”?
一点点基准测试:上面的代码花了大约 0.4 秒。相比之下,我的第一个建议textread
在同一个文件上花费了大约 9 秒;你的原始代码用了 11 秒多一点。当文件变大时,差异可能会变大。
如果您经常这样做(如您所说),显然值得将您的文件一次转换为二进制格式,然后以这种方式使用它们。特别是如果文件只需要转换一次,并且需要多次读取,节省的费用将是相当可观的。
更新
我用一个 13M 的行文件重复了基准测试。转换耗时 13 秒,二进制读取 < 3 秒。相比之下,其他两种方法中的每一种都花费了一分钟(textscan:61s;fscanf:77s)。似乎事情是线性缩放的(文件大小 470M 文本,240M 二进制)