使用C读取.mat文件:如何正确读取单元格结构

时间:2015-04-12 22:24:46

标签: c matlab

我基本上试图在C代码中翻译Matlab代码。这是我之前question的扩展名。

在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 

另外,我也无法正确阅读此字段:Creator ='DKumar';

更新:

基于@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])?

1 个答案:

答案 0 :(得分:5)

结果稍有变化,您的代码可以运行:

在功能&#34; void matread_Cell&#34;将行double* p2 = (double*)cellArray[CellIndex];替换为:

p2 = (double*) mxGetPr(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,我收到错误:&#34;被释放的指针未被分配&#34;,所以我认为你不需要释放它。另一个释放动态内存的有用命令是:void mxFree(void *ptr);

关于mexPrintf函数,我实际上可以使用它。我只是收到警告implicit declaration of function 'mexPrintf' is invalid in C99 [-Wimplicit-function-declaration],因为我是通过gcc而不是mex编译的。如果您使用的是gcc,则可能需要包含适当的库来识别该功能。您可能会发现this很有用,因为它对我有用。