2015-04-12 68 views
13

我基本上试图在C代码中转换Matlab代码。这是我以前的question的延伸。使用C读取.mat文件:如何正确读取单元结构

在Matlab中,我已经使用cell-structures保持matrices (double) of variable sizes。这里是什么我* .MAT文件supposed to store玩具例子:

MATLAB代码:

A = [[1 2 3]; [5 7 1]; [3 5 9]]; 
B = [[2 4];[5 7]]; 
Creator = 'DKumar'; 

nFilters = 2; 

Filters{1} = [[-1.0 -1.0 -1.0]; [-1.0 8 -1.0]; [-1.0 -1.0 -1.0]]; 
Filters{2} = 2.0*[[-1.0 -1.0]; [-1.0 8]; [-1.0 -1.0]]; 

cd('/home/dkumar/CPP_ExampleCodes_DKU/Read_mat_File'); 
save('Test_FILE.mat', 'A', 'B', 'Creator', 'nFilters', 'Filters'); 

C代码:功能"matread_Matrix" reads matrices stored in *.mat properly。这是功能"matread_Cell",它应该读取单元结构,是not working

#include <stdio.h> 
#include <stdlib.h> 
#include "/usr/local/MATLAB/R2011b/extern/include/mat.h" 

mxArray *arr; 
mxArray *C_CELL; 
/* declare a 2 x 1 array of pointers to access the cell array in C */ 
mxArray *cellArray[2]; 

struct stDoubleMat{ 
    double* pValueInField; 
    int nRows, nCols; 
}; 

void matread_Matrix(const char *file, const char *FieldName2Read, struct stDoubleMat* poDoubleMat_LOC) 
{ 
    printf("Reading file %s...\n\n", file); 

    //Open file to get directory 
    MATFile* pmat = matOpen(file, "r"); 

    if (pmat == NULL) { 
     printf("Error opening file %s\n", file); 
     return; 
    } 

    // extract the specified variable 
    arr = matGetVariable(pmat, FieldName2Read); 

    double *pr; 
    if (arr != NULL && !mxIsEmpty(arr)) { 
     // copy data 
     mwSize num = mxGetNumberOfElements(arr); 

     pr = mxGetPr(arr); 

     if (pr != NULL) { 
     poDoubleMat_LOC->pValueInField = pr; 
      poDoubleMat_LOC->nRows = mxGetM(arr); 
      poDoubleMat_LOC->nCols = mxGetN(arr); 
     } 
    printf("matread_Matrix \n") ; 
     printf("oDoubleMat_LOC.nRows %i ; oDoubleMat_LOC.nCols %i \n", poDoubleMat_LOC->nRows , poDoubleMat_LOC->nCols); 

    }else{ 
     printf("nothing to read \n") ; 
    } 


    // close the file 
    matClose(pmat); 

    return; 
} 

void matread_Cell(const char *file, const char *FieldName2Read, int CellIndex) 
{ 
    printf("Reading file %s...\n\n", file); 

    //Open file to get directory 
    MATFile* pmat = matOpen(file, "r"); 

    if (pmat == NULL) { 
     printf("Error opening file %s\n", file); 
     return; 
    } 

    // extract the specified variable 
    C_CELL = matGetVariable(pmat, FieldName2Read); 
    cellArray[CellIndex] = mxGetCell(C_CELL, CellIndex); 

    double* p2 = (double*)cellArray[CellIndex]; 
    int nRows = mxGetM(cellArray[CellIndex]); 
    int nCols = mxGetN(cellArray[CellIndex]); 

    printf(" From inside matread_Cell : nRows %i and nCols %i \n", nRows, nCols); 

    int i2; 
    for (i2 = 0; i2 < nRows*nCols; i2++) 
    { 
    printf(" copied value : %f \n", *p2); 
    p2 = p2 +1; 
    } 

    // close the file 
    matClose(pmat); 
} 


int main(int argc, char **argv) 
{ 
    const char *FileName = "/home/dkumar/CPP_ExampleCodes_DKU/Read_mat_File/Test_FILE.mat"; 
    const char *FieldName2Read = "A"; 

    struct stDoubleMat oDoubleMat; 
    matread_Matrix(FileName, FieldName2Read, &oDoubleMat); 
    double* v = oDoubleMat.pValueInField; 


    printf("From main \n"); 
    printf("oDoubleMat.nRows %i ; oDoubleMat.nCols %i \n", oDoubleMat.nRows , oDoubleMat.nCols); 

    int i; 
    for (i = 0; i < oDoubleMat.nCols*oDoubleMat.nRows; i++) 
    { 
     printf(" copied value : %f \n", *v); 
     v = v +1; 
    } 

    // Reading the structure 
    const char *FieldName2Read2 = "Filters"; 
    matread_Cell(FileName, FieldName2Read2, 0); 
    matread_Cell(FileName, FieldName2Read2, 1); 


    // cleanup the mex-array 
    mxDestroyArray(arr); 
    mxDestroyArray(C_CELL); 
    /* How to delete mxArray of pointer : should this be a array of pointers */ 
    //mxDestroyArray(cellArray[0]); 
    //mxDestroyArray(cellArray[1]); 

    return 0; 
} 

输出:

$ gcc -g -o Test Read_MatFile_DKU_2.c -I/usr/local/MATLAB/R2011b/extern/include -L/usr/local/MATLAB/R2011b/bin/glnxa64 -lmat -lmx 

$ ./Test 
Reading file /home/dkumar/CPP_ExampleCodes_DKU/Read_mat_File/Test_FILE.mat... 

matread_Matrix 
oDoubleMat_LOC.nRows 3 ; oDoubleMat_LOC.nCols 3 
From main 
oDoubleMat.nRows 3 ; oDoubleMat.nCols 3 
copied value : 1.000000 
copied value : 5.000000 
copied value : 3.000000 
copied value : 2.000000 
copied value : 7.000000 
copied value : 5.000000 
copied value : 3.000000 
copied value : 1.000000 
copied value : 9.000000 
Reading file /home/dkumar/CPP_ExampleCodes_DKU/Read_mat_File/Test_FILE.mat... 

From inside matread_Cell : nRows 3 and nCols 3 
copied value : 0.000000 
copied value : 0.000000 
copied value : 0.000000 
copied value : 0.000000 
copied value : 0.000000 
copied value : 0.000000 
copied value : 0.000000 
copied value : 0.000000 
copied value : 0.000000 
Reading file /home/dkumar/CPP_ExampleCodes_DKU/Read_mat_File/Test_FILE.mat... 

From inside matread_Cell : nRows 3 and nCols 2 
copied value : 0.000000 
copied value : 0.000000 
copied value : 0.000000 
copied value : 0.000000 
copied value : 0.000000 
copied value : 0.000000 

另外,我不能读取该字段适当地以及:创建者= 'DKumar';

UPDATE:基于@Sherwin的建议

我的C代码:

#include <stdio.h> 
#include <stdlib.h> 
#include "/usr/local/MATLAB/R2011b/extern/include/mat.h" 

mxArray *arr; 
mxArray *C_CELL; 
/* declare a 2 x 1 array of pointers to access the cell array in C */ 
mxArray *cellArray[2]; 

struct stDoubleMat{ 
    double* pValueInField; 
    int nRows, nCols; 
}; 


void matread_Matrix(MATFile* pmat , const char *FieldName2Read, struct stDoubleMat* poDoubleMat_LOC) 
{ 
    // extract the specified variable 
    arr = matGetVariable(pmat, FieldName2Read); 

    double *pr; 
    if (arr != NULL && !mxIsEmpty(arr)) { 
     // copy data 
     mwSize num = mxGetNumberOfElements(arr); 

     pr = mxGetPr(arr); 

     if (pr != NULL) { 
     poDoubleMat_LOC->pValueInField = pr; 
      poDoubleMat_LOC->nRows = mxGetM(arr); 
      poDoubleMat_LOC->nCols = mxGetN(arr); 
     } 
    printf("matread_Matrix \n") ; 
     printf("oDoubleMat_LOC.nRows %i ; oDoubleMat_LOC.nCols %i \n", poDoubleMat_LOC->nRows , poDoubleMat_LOC->nCols); 

    }else{ 
     printf("nothing to read \n") ; 
    } 
    return; 
} 

void matread_String(MATFile* pmat , const char *FieldName2Read) 
{ 
    // extract the specified variable 
    arr = matGetVariable(pmat, FieldName2Read); 

    double *pr; 
    if (arr != NULL && !mxIsEmpty(arr)) { 
     // copy data 
     mwSize num = mxGetNumberOfElements(arr); 
     pr = mxGetPr(arr); 

     if (pr != NULL) { 
      char *p2 = (char*) pr; 

      // Printing and checking 
     int i2; 
     for (i2 = 0; i2 < num; i2++) 
     { 
     printf(" copied value : %s \n", p2); 
     p2 = p2 +1; 
     } 

    } 

    }else{ 
      printf("nothing to read \n") ; 
    } 
    return; 
} 

void matread_Cell(MATFile* pmat , const char *FieldName2Read, int CellIndex) 
{ 

    // extract the specified variable 
    C_CELL = matGetVariable(pmat, FieldName2Read); 
    cellArray[CellIndex] = mxGetCell(C_CELL, CellIndex); 

    double *p2 = (double*) mxGetPr(cellArray[CellIndex]); 
    int nRows = mxGetM(cellArray[CellIndex]); 
    int nCols = mxGetN(cellArray[CellIndex]); 

    printf(" From inside matread_Cell : nRows %i and nCols %i \n", nRows, nCols); 

    int i2; 
    for (i2 = 0; i2 < nRows*nCols; i2++) 
    { 
    printf(" copied value : %f \n", *p2); 
    p2 = p2 +1; 
    } 
} 


int main(int argc, char **argv) 
{ 
    const char *FileName = "/home/dkumar/CPP_ExampleCodes_DKU/Read_mat_File/Test_FILE.mat"; 
    const char *FieldName2Read = "A"; 

    //Open file to get directory 
    printf("Reading file %s...\n\n", FileName); 
    MATFile* pmat = matOpen(FileName, "r"); 

    if (pmat == NULL) { 
     printf("Error opening file %s\n", FileName); 
     return; 
    } 

    struct stDoubleMat oDoubleMat; 
    matread_Matrix(pmat, FieldName2Read, &oDoubleMat); 
    double* v = oDoubleMat.pValueInField; 

    int i; 
    for (i = 0; i < oDoubleMat.nCols*oDoubleMat.nRows; i++) 
    { 
     printf(" copied value : %f \n", *v); 
     v = v +1; 
    } 

    // Reading the structure 
    const char *FieldName2Read2 = "Filters"; 
    matread_Cell(pmat, FieldName2Read2, 0); 
    matread_Cell(pmat, FieldName2Read2, 1); 

    // Reading the string 
    const char *FieldName2Read3 = "Creator"; 
    matread_String(pmat, FieldName2Read3); 

    // cleanup the mex-array 
    mxDestroyArray(arr); 
    mxDestroyArray(C_CELL); 

    /* How to delete mxArray of pointer : should this be a array of pointers */ 
    //mxDestroyArray(cellArray[0]); 
    //mxDestroyArray(cellArray[1]); 


    // close the file 
    matClose(pmat); 

    return 0; 
} 

输出:

oDoubleMat.nRows 3 ; oDoubleMat.nCols 3 
copied value : 1.000000 
copied value : 5.000000 
copied value : 3.000000 
copied value : 2.000000 
copied value : 7.000000 
copied value : 5.000000 
copied value : 3.000000 
copied value : 1.000000 
copied value : 9.000000 
From inside matread_Cell : nRows 3 and nCols 3 
copied value : -1.000000 
copied value : -1.000000 
copied value : -1.000000 
copied value : -1.000000 
copied value : 8.000000 
copied value : -1.000000 
copied value : -1.000000 
copied value : -1.000000 
copied value : -1.000000 
From inside matread_Cell : nRows 3 and nCols 2 
copied value : -2.000000 
copied value : -2.000000 
copied value : -2.000000 
copied value : -2.000000 
copied value : 16.000000 
copied value : -2.000000 
copied value : D 
copied value : 
copied value : K 
copied value : 
copied value : u 
copied value : 
copied value : 

问题:1)字符串值存储在创造者没有正确显示。

2)如何删除cellArray [2])?

+0

如果你在Matlab之外读取数据,你为什么要将数据保存为“MAT”格式?为什么不将数据(在Matlab中)导出到例如hdf5并使用现有工具读取hdf5二进制数据? – Shai

+0

我从来没有使用hdf5格式,我不知道它是否可以存储和访问单元格结构。 –

+2

Matlab将其MAT文件保存为hdf5格式(适用于版本7.3及以上,AFAIK)。所以,原则上它可以做任何你需要的。你将不得不弄脏自己的手并学习如何连接到hdf5,但考虑到你正在经历与MAT格式相同(痛苦)的过程,我认为你会更好地学习更多功能的工具( HDF5),而不是专注于非常有限的MAT ...但这只是我的看法。 – Shai

回答

5

原来有轻微的改变,你的代码工作:

p2 = (double*) mxGetPr(cellArray[CellIndex]); 

我检查出来:

在功能“void matread_Cell”替换行double* p2 = (double*)cellArray[CellIndex];。它完成了这项工作。

而且读的创造者领域,类似的代码来mtread_matrix应该工作,只是类型为char*,而不是double*(我没有检查这一项,虽然。让我知道,如果它不工作)。

更新:您可以使用下面的代码来读取字符串。(参考:here

void matread_string(const char *file, const char *FieldName2Read, char *pr, mwSize *len) 
{ 
    printf("Reading file %s...\n\n", file); 

    //Open file to get directory 
    MATFile* pmat = matOpen(file, "r"); 

    if (pmat == NULL) { 
     printf("Error opening file %s\n", file); 
     return; 
    } 

    // extract the specified variable 
    arr = matGetVariable(pmat, FieldName2Read); 

    if (arr != NULL && !mxIsEmpty(arr)) { 
     // copy data 
     mwSize num = mxGetNumberOfElements(arr); 

     //int mxGetString(const mxArray *pm, char *str, mwSize strlen); 
     int res= mxGetString(arr, pr, num+1); //strlen should be len+1. c.f. reference. 
     if(res==0) 
      printf("success!\n"); 
     else 
      printf("failed.\n"); 


     if (pr == NULL){ 
      printf("null pointer.\n"); 
     } 
     printf("matread_string \n") ; 
     printf("len: %i \n", (int)num); 

     *len=num; 

    }else{ 
     printf("nothing to read \n") ; 
    } 
    // close the file 
    matClose(pmat); 

    return; 
} 

main你可以用它喜欢:

const char *FieldName2Read3 = "Creator"; 
    char pr[20]; 
    mwSize len; 
    matread_string(FileName, FieldName2Read3, pr, &len); 

    //int i; 
    printf(" copied value: %s \n",pr); 
    for (i = 0; (mwSize) i < len; i++) 
    { 
     printf(" copied value : %c \n", pr[i]); 
    } 

关于解除分配cellArray,我得到的错误: “被释放的指针是未分配”,所以我不你认为你需要释放它。释放动态内存的另一个有用命令是:void mxFree(void *ptr);

关于mexPrintf函数,我实际上可以使用它。我只是得到了一个警告implicit declaration of function 'mexPrintf' is invalid in C99 [-Wimplicit-function-declaration],因为我通过gcc而不是mex编译。如果你使用的是gcc,你可能需要包含合适的库来识别这个函数。您可能会发现this有用,因为它为我工作。

+0

我更新了我的代码根据您的建议,我可以读取CellArray,仍然无法读取字符串。另外,我不知道如何删除cellArray [2])。另外,我宁愿使用mexPrintf。但是,我收到一个错误:未定义的引用“mexPrintf”。 对此有何猜测? –

+0

我将更新添加到我的答案中。 – Shervin