在Matlab上从二进制文件中读取稀疏数组

时间:2015-06-08 19:53:58

标签: arrays matlab

我必须编写一个函数,它从一个binary file (.dat)结构中读取一个二维的双精度数组,该列由一个单独的列组成,其名称由函数的单个输入参数提供。该文件的格式如下: 首先,有两个uint32数字对应于数组的行数和列数。之后,有一个双数,即数组中非零元素的数量。然后,数组中的每个非零元素由两个uint32标量和文件中的双标量按此顺序表示:其行索引(uint32),其列索引(uint32)及其值(double)。一个例子可能是:

5
4
2
1
1
8
2
2
9

这意味着该数组有5行4列,总共2个非零元素。这些元素位于(1,1)位置(值为8)和位置(2,2)(值为9)。所有其他元素都等于0.因此,数组将是:

8  0  0  0
0  9  0  0
0  0  0  0
0  0  0  0
0  0  0  0

该函数必须返回它从文件中读取的二维数组作为输出参数,如果打开文件时出现问题,该函数将返回一个空数组。目前我尝试使用此代码:

function A = sparse_array_in( filename )
fid = fopen( filename,'rt' );
if fid < 0
    A = [];
    return;
end
% Get total number of elements on the file
n = 0;
while (fgets(fid) ~= -1),
  n = n+1;
end
% Close then reopen
fclose(fid);
fid = fopen( filename,'rt' );
% Read size of array and number of non-zero elements
rows = fread( fid,1,'uint32' );
cols = fread( fid,1,'uint32' );
dims = [ rows,cols ];
non_zero = fread( fid,1,'uint32' );
% Create array of zeros
A = zeros( dims );   
% Fill array A with the values from the file
for i = 1:non_zero
    r = fread( fid,1,'uint32' );
    c = fread( fid,1,'uint32' );
    v = fread( fid,1,'double' );
    A(r,c) = v;
end
fclose( fid );
end

但它似乎无法正常工作。我错过了什么?

1 个答案:

答案 0 :(得分:2)

您的代码存在一些问题:

  1. 如果文件ID为负数,则不仅要返回空数组(正如您所做的那样),还要确保代码从该点开始。我会在分配到return后立即发表A声明:

    if fid < 0
        A = [];
        return;
    end
    
  2. 接下来当您确定文本文件中的行数时,请注意每次调用fgets时都要推进文件指针,这样当您最终完成所有行,文件指针指向文本文件的末尾。对freadfgets或任何从文件中读取内容的f*系列的任何进一步调用都不会为您提供任何内容,因为您位于文件的末尾。您需要做的是关闭文件并再次打开,以便您可以再次从文件中读取。因此,在读取行数时关闭文件,然后再次打开它:

    % Get total number of elements on the file
    n = 0;
    while (fgets(fid) ~= -1),
      n = n+1;
    end 
    %// Close then reopen
    fclose(fid);
    fid = fopen( filename,'rt');
    
  3. 您没有使用fread权利。第二个参数告诉您要读入的特定类型的数量数字。您使用的是1,2或3,这意味着您正在读取特定类型的1,2或3个数字。由于您使用fread来读取每次通话的个别号码,因此全部为1 。此外,确定线路总数对我来说似乎是多余的。如果给出非零元素的总数,为什么还要弄清楚有多少行?您已经知道有多少非零元素,因此只需从1到非零数字迭代。因此,试试这个:

    % Read size of array and number of non-zero elements
    rows = double(fread( fid,1,'uint32' )); %// Change
    cols = double(fread( fid,1,'uint32' )); %// Change
    dims = [ rows,cols ];
    non_zero = fread( fid,1,'uint32' ); %// Change
    % Create array of zeros
    A = zeros( dims );   
    % Fill array A with the values from the file
    for i = 1 : non_zero %// Change
        r = fread( fid,1,'uint32' ); %// Change
        c = fread( fid,1,'uint32' ); %// Change
        v = fread( fid,1,'double' ); %// Change
        A(r,c) = v;
    end
    %A = reshape( A,dims' ); %// Why are you reshaping?
    fclose( fid );
    
  4. 次要评论:你为什么重塑矩阵?如果您已经知道矩阵的行和列位置,并将它们准确地放在它们应该去的位置,为什么还要转置?

    因此,通过上述注释,您的代码将如下所示:

    function A = sparse_array_in( filename )
    fid = fopen( filename,'rt' );
    if fid < 0
        A = [];
        return; %// Change
    end
    
    % Read size of array and number of non-zero elements
    rows = fread( fid,1,'uint32'); %// Change
    cols = fread( fid,1,'uint32'); %// Change
    dims = [ rows,cols ];
    non_zero = fread( fid,1,'uint32' ); %// Change
    % Create array of zeros
    A = zeros( dims );   
    % Fill array A with the values from the file
    for i = 1:non_zero
        r = fread( fid,1,'uint32' ); %// Change
        c = fread( fid,1,'uint32' ); %// Change
        v = fread( fid,1,'double' ); %// Change
        A(r,c) = v;
    end
    %// Change - remove reshape
    fclose( fid );
    end
    

    这是一个示例,表明它适用于二进制文件。我创建了以下场景:

    5
    7
    4
    1
    1
    1
    2
    2
    2
    3
    3
    3
    4
    4
    4
    

    这是一个5 x 7矩阵,其中(1,1) = 1, (2,2) = 2, (3,3) = 3, (4,4) = 4有4个非零值。我创建了一个二进制文件,然后使用我上面修复的函数来获得结果:

    fid = fopen('sparse_binary.dat', 'w');
    fwrite(fid, 5, 'uint32');
    fwrite(fid, 7, 'uint32');
    fwrite(fid, 4, 'uint32');
    fwrite(fid, 1, 'uint32');
    fwrite(fid, 1, 'uint32');
    fwrite(fid, 1, 'double');
    fwrite(fid, 2, 'uint32');
    fwrite(fid, 2, 'uint32');
    fwrite(fid, 2, 'double');
    fwrite(fid, 3, 'uint32');
    fwrite(fid, 3, 'uint32');
    fwrite(fid, 3, 'double');
    fwrite(fid, 4, 'uint32');
    fwrite(fid, 4, 'uint32');
    fwrite(fid, 4, 'double');
    fclose(fid);
    A = sparse_array_in('sparse_binary.dat');
    

    我选择A

    A =
    
         1     0     0     0     0     0     0
         0     2     0     0     0     0     0
         0     0     3     0     0     0     0
         0     0     0     4     0     0     0
         0     0     0     0     0     0     0
    

    ......这就是我们所期望的。