我正在尝试将一个大文本文件(几百万行)读入 Matlab。最初我使用的是importdata(file_name),这似乎是一个简洁的解决方案。但是我需要使用 Matlab 7(是的,我知道它的旧版本),而且似乎不支持导入数据。因此,我尝试了以下方法:
while ~feof(fid)
fline = fgetl(fid);
fdata{1,lno} = fline ;
lno = lno + 1;
end
但这真的很慢。我猜是因为它在每次迭代时都会调整数组的大小。有没有更好的方法。请记住,输入数据的前 20 行是字符串类型数据,其余数据是 3 到 6 列十六进制值。
做一些重塑,但你的另一个选择是你可以使用fread。但如前所述,这基本上将您锁定在矩形导入中。所以另一种选择是使用文本扫描。正如我在另一篇说明中提到的,我不是 100% 确定它是何时实现的,我只知道你没有"importdata()"
fid = fopen('textfile.txt')
Out = textscan(fid,'%s','delimiter',sprintf('n'));
fclose(fid)
通过使用TextScan,您将能够为每行获取一个字符的单元格数组,然后您可以根据需要进行操作。正如我在评论中所说,线条是否相同长度不再重要。 现在,您可以更快地解析单元格数组。但正如 gnovice 提到的,而且他也确实有一个非常优雅的解决方案,你可能不得不关注内存需求。
如果你能避免的话,你永远不想在 matlab 中使用的一件事就是循环结构。它们在 C/C++ 等中速度很快,但在 matlab 中,它们是到达您要去的地方的最慢方式。
编辑:刚刚查了一下,看起来textscan是在版本7(R14)中实现的,所以如果这就是你所拥有的,你应该很好地使用它。
我看到两个选项:
- 例如,您可以
- 仅在必要时将数组的大小增加一倍,而不是每次都增长 1。 这大大减少了所需的重新分配数量。
- 执行两遍方法。 第一遍只是计算行数,而不存储它们。 第二次传递实际上填充数组(已预先分配给正确的大小)。
一种解决方案是使用 FSCANF 将文件的全部内容读取为字符串,使用 MAT2CELL 将字符串拆分为出现换行符的点的单个单元格,使用 STRTRIM 删除末端多余的空格,然后根据需要处理每个单元格中的字符串数据。例如,使用此示例文本文件'junk.txt'
:
hi
hello
1 2 3
FF 00 FF
12 A6 22 20 20 20
FF FF FF
以下代码会将每一行放在单元格数组cellData
的单元格中:
>> fid = fopen('junk.txt','r');
>> strData = fscanf(fid,'%c');
>> fclose(fid);
>> nCharPerLine = diff([0 find(strData == char(10)) numel(strData)]);
>> cellData = strtrim(mat2cell(strData,1,nCharPerLine))
cellData =
'hi' 'hello' '1 2 3' 'FF 00 FF' '12 A6 22 20 20 20' 'FF FF FF'
现在,如果要将所有十六进制数据(我的示例数据文件中的第 3 行到第 6 行)从字符串转换为数字向量,您可以使用 CELLFUN 和 SSCANF,如下所示:
>> cellData(3:end) = cellfun(@(s) {sscanf(s,'%x',[1 inf])},cellData(3:end));
>> cellData{3:end} %# Display contents
ans =
1 2 3
ans =
255 0 255
ans =
18 166 34 32 32 32
ans =
255 255 255
注意
:由于您正在处理如此大的数组,因此您必须注意变量使用的内存量。上述解决方案是矢量化的,但可能会占用大量内存。创建cellData
时,您可能必须覆盖或清除strData
等大型变量。或者,您可以遍历nCharPerLine
中的元素,并将较大字符串的每个段单独处理strData
到所需的向量中,现在您可以预先分配这些向量,因为您知道您有多少行数据(即 nDataLines = numel(nCharPerLine)-nHeaderLines;
)。