【发布时间】:2013-11-03 21:26:12
【问题描述】:
我正在解析一个充满数据的大型文本文件,然后将其作为 *.mat 文件保存到磁盘,以便我可以轻松地仅加载其中的一部分(有关读取文件的更多信息,请参阅here,和here 用于数据)。为此,我一次读取一行,解析该行,然后将其附加到文件中。问题是文件本身比其中包含的数据大>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 字节?我知道帮助页面说应该有一点额外的开销,但我觉得近 Gb 的描述性标题有点过分!
新信息:
我尝试预先分配文件,认为当矩阵在一个循环中嵌入并在每次写入时为整个矩阵重新分配一块磁盘空间时,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 格式不是默认格式。有谁知道解决这个问题的方法?这是错误还是功能?
【问题讨论】:
-
您的操作系统说明磁盘上实际使用了多少空间?
-
857,185Kb(Windows 7 64 位,MATLAB 2013a 64 位)
-
在我看来确实是个 bug,但你可以通过分块编写来绕过它。我尝试了 10,000 个块,文件大小合理。
-
我正在使用的这个测试文件可能都适合内存,但这是一个完整的 HITRAN 2012 数据库的测试用例,它是一个 700 Mb 的文本文件。将其加载到内存中,然后将其拆分为不同的变量,然后将其保存到磁盘,它使我的计算机瘫痪了。第一次尝试时,我不得不进行硬重置并丢失了一堆其他工作。
-
这就是诀窍。我没有足够的内存来避免它。我的主要目标是将数据文件转换为 matlab 二进制文件,我可以在其中加载单个变量,比如行频或分子,搜索标准,如范围或同位素,然后仅加载该部分满足条件的数据库。以本机文本形式,我必须将整个内容加载到内存中(或者进行逐行搜索,这需要花费大量时间。如果我可以将其转换为与
matfile命令兼容的合理大小的二进制文件,这样可以节省时间和内存。
标签: matlab