我编写了这段代码,它的工作正常,但对我的目的来说太慢了:
%%% load nodal data %%%
path = sprintf('%sfile.dat',directory);
fid = fopen(path);
num_nodes = textscan(fid,'%s %s %s %s %d',1,'delimiter', ' ');
num_nodes = num_nodes{5};
header = textscan(fid,'%s',7,'delimiter', '\t');
k = 0;
while ~feof(fid)
line = fgetl(fid);
[head,rem] = strtok(line,[' ',char(9)]);
if head == '#'
k = k+1;
j = 1;
time_steps(k) = sscanf(rem, [' Output at t = %d']);
end
if ~isempty(head)
if head ~= '#'
data(j,:,k) = str2num([head rem]);
j = j+1;
end
end
end
fclose(fid);
nodal_data = struct('header',header,'num_nodes',num_nodes,'time_steps',time_steps,'data',data);
我正在阅读Matlab的ascii看起来像这样:
# Number of Nodes: 120453
#X Y Z depth vel_x vel_y wse
# Output at t = 0
76456.003 184726 3815.75 0 0 0 3815.75
76636.003 184726 3728.25 0 0 0 3728.25
76816.003 184726 3627 0 0 0 3627
76996.003 184726 3527.75 0 0 0 3527.75
77176.003 184726 3371.5 0 0 0 3371.5
# Output at t = 36000.788
76456.003 184726 3815.75 0 0 0 3815.75
76636.003 184726 3728.25 0 0 0 3728.25
76816.003 184726 3627 0 0 0 3627
76996.003 184726 3527.75 0 0 0 3527.75
77176.003 184726 3371.5 0 0 0 3371.5
虽然我编写的代码适用于非常小的文件,但是对于更大的ascii文件,它会让我感到震惊。我已经不得不中止加载~25mb ascii(大约240k行),这只是一个测试文件。该文件的更新版本将是~500mb。有没有办法加快加载文件的过程我对3 if语句不满意,但我不知道如何用开关打开数字来分隔'#',特别是因为我无法通过类来区分'head',即我试图检查ischar或isnumeric,但是当变量'head'被读作字符串时,它始终是ischar
的情况,永远不会{{1} } = isnumeric
。我也不太乐意使用一个标记器来使用if-cases,然后在这里放置一行:true
,因为这可能会消耗很多时间。但是,我不知道怎么做。
因此,如果您对如何调整我的代码有任何有用的建议,我将非常感谢他们!
祝你周日愉快,并提前感谢你!
答案 0 :(得分:2)
下面的代码读取大约70000次步长,每步5个节点,大约7秒钟。它完成了代码所做的大部分工作,并且应该很容易添加代码的额外功能。还有其他方法可以更快地完成这项工作,但希望这应该足够了。
filename = 'd:\temp\input.txt';
filetext = fileread(filename);
headerLines = 2;
valuesPerLine = 7;
expr = '[^\n]*[^\n]*';
lines = regexp(filetext, expr, 'match');
isTimeStep = cellfun(@(x) strncmp(x,'#',1), lines );
numTimeSteps = sum(isTimeStep)-headerLines;
nodesPerStep = ((length(lines)-headerLines) / numTimeSteps ) - 1;
data = zeros(nodesPerStep, valuesPerLine, numTimeSteps);
for timeStep = 1:numTimeSteps
lineIndex = headerLines + (timeStep-1) * (nodesPerStep + 1) + 2;
for node = 1:nodesPerStep
data(node, :, timeStep ) = sscanf(lines{lineIndex},'%f');
lineIndex = lineIndex + 1;
end
end
刚试了200万行文件(340000个步骤,每步5个节点),大约需要36秒才能运行。
如果您想要一个没有编码循环的解决方案,您可以从
中的代码替换data = zeros(....
与
values = cellfun(@(x) sscanf(x,'%f'),lines(~isTimeStep),'uniformoutput',false);
data = reshape(cell2mat(values), nodesPerStep, valuesPerLine, numTimeSteps);
但运行时间要长约50%。
答案 1 :(得分:1)
更改任何内容之前要做的第一件事是 PRE-ALLOCATE 所有输出数组:
您的代码输出time_steps
和data
,所有这些都在循环中生长。这会让你失去性能。
假设每个时间步之间总共有五行。
在循环
之前添加以下行data = reshape( NaN( num_nodes, 7 ), [], 7, 5 ); % assuming 7 columns and 5 lines for each time step
time_steps = NaN( num_nodes / 5 );
循环之后只丢弃剩余的NaN
data( isnan(data) ) = [];
time_step( isnan(time_step) ) = [];