我正在解析一个大型的文本文件,其中充满了数据,然后将其保存为*.mat文件,以便我可以轻松地只加载其中的部分内容(有关读取文件的更多信息,请参见此处,有关数据,请参见此处)。为此,我一次读入一行,解析该行,然后将其附加到文件中。问题在于,文件本身比其中包含的数据大了3个数量级以上!
以下是我的代码简化版本:
以下是我的代码简化版本:
database = which('01_hit12.par');
[directory,filename,~] = fileparts(database);
matObj = matfile(fullfile(directory,[filename '.mat']),'Writable',true);
fidr = fopen(database);
hitranTemp = fgetl(fidr);
k = 1;
while ischar(hitranTemp)
if abs(hitranTemp(1)) == 32;
hitranTemp(1) = '0';
end
hitran = textscan(hitranTemp,'%2u%1u%12f%10f%10f%5f%5f%10f%4f%8f%15c%15c%15c%15c%6u%2u%2u%2u%2u%2u%2u%1c%7f%7f','delimiter','','whitespace','');
matObj.moleculeNumber(1,k) = uint8(hitran{1});
matObj.isotopeologueNumber(1,k) = uint8(hitran{2});
matObj.vacuumWavenumber(1,k) = hitran{3};
matObj.lineIntensity(1,k) = hitran{4};
matObj.airWidth(1,k) = single(hitran{6});
matObj.selfWidth(1,k) = single(hitran{7});
matObj.lowStateE(1,k) = single(hitran{8});
matObj.tempDependWidth(1,k) = single(hitran{9});
matObj.pressureShift(1,k) = single(hitran{10});
if rem(k,1e4) == 0;
display(sprintf('line %u (%2.2f)',k,100*k/K));
end
hitranTemp = fgetl(fidr);
k = k + 1;
end
fclose(fidr);
由于代码解析时间过长且文件大小正在变得非常庞大,因此当解析了224,515行中的13,813行后我停止了代码。但是最后的输出表明我仅刚刚清除了10k行。我清除了内存,然后运行了以下命令:
S = whos('-file','01_hit12.mat');
fileBytes = sum([S.bytes]);
T = dir(which('01_hit12.mat'));
diskBytes = T.bytes;
disp([fileBytes diskBytes diskBytes/fileBytes])
并获得输出:
524894 896189009 1707.37141022759
为什么会多出895,664,115字节的空间?我知道帮助页面上说应该会有一些额外的开销,但是我觉得近1GB的描述性头部有点过分了!
新信息:
我尝试预先分配文件,认为也许MATLAB在执行循环时对于矩阵进行扩展时会做同样的事情,并在每次写入时重新分配整个矩阵的磁盘空间,但这不是原因。用适当数据类型的零填充文件会使我的简短检查脚本返回以下结果:
8531570 71467 0.00837677004349727
这对我来说更有意义。Matlab正在稀疏地保存文件,因此磁盘文件大小比内存中完整矩阵的大小小得多。然而,一旦开始用实际数据替换值,文件大小就会开始飙升超出所有合理的界限。
新的新信息:
在数据的子集上尝试了这个方法,长度为100行。要流式传输到磁盘,数据必须采用v7.3格式,因此我将子集通过我的脚本运行,加载到内存中,然后重新保存为v7.0格式。以下是结果:
v7.3: 3800 8752 2.30
v7.0: 3800 2561 0.67
难怪v7.3格式不是默认的。有人知道解决这个问题的方法吗?这是一个错误还是一个特性?
v7.3
的压缩,或者说缺乏压缩,非常糟糕。我记得之前向MathWorks抱怨过这个问题,他们回复说这会增加开销! - chappjc