Считайте текстовый файл

Этот пример показывает, как сгенерировать автономную библиотеку C из кода MATLAB, который читает файл из диска с помощью функций fopen/fread/fclose.

О функции readfile

Функция readfile.m берет имя файла (или путь), как введено и возвращает строку, содержащую содержимое файла.

type readfile
% y = readfile(filename)
% Read file 'filename' and return a MATLAB string with the contents
% of the file.
function y = readfile(filename) %#codegen

% Put class and size constraints on function input.
assert(isa(filename, 'char'));
assert(size(filename, 1) == 1);
assert(size(filename, 2) <= 1024);

% Call fopen(filename 'r'), but we need to convert the MATLAB
% string into a C type string (which is the same string with the
% NUL (\0) string terminator).
f = fopen(filename, 'r');

% Call fseek(f, 0, SEEK_END) to set file position to the end of
% the file.
fseek(f, 0, 'eof');

% Call ftell(f) which will return the length of the file in bytes
% (as current file position is at the end of the file).
filelen = int32(ftell(f));

% Reset current file position
fseek(f,0,'bof');

% Initialize a buffer
maxBufferSize = int32(2^16);
buffer = zeros(1, maxBufferSize,'uint8');

% Remaining is the number of bytes to read (from the file)
remaining = filelen;

% Index is the current position to read into the buffer
index = int32(1);

while remaining > 0
    % Buffer overflow?
    if remaining + index > size(buffer,2)
        fprintf('Attempt to read file which is bigger than internal buffer.\n');
        fprintf('Current buffer size is %d bytes and file size is %d bytes.\n', maxBufferSize, filelen);
        break
    end
    % Read as much as possible from the file into internal buffer

    [dataRead, nread] = fread(f,remaining, 'char');
    buffer(index:index+nread-1) = dataRead;
    n = int32(nread);
    if n == 0
        % Nothing more to read
        break;
    end
    % Did something went wrong when reading?
    if n < 0
        fprintf('Could not read from file: %d.\n', n);
        break;
    end
    % Update state variables
    remaining = remaining - n;
    index = index + n;
end

% Close file
fclose(f);

y = char(buffer(1:index));

Сгенерируйте MEX-функцию для тестирования

Сгенерируйте MEX-функцию с помощью команды codegen.

codegen readfile

Прежде, чем сгенерировать код С, необходимо сначала протестировать MEX-функцию в MATLAB, чтобы гарантировать, что это функционально эквивалентно оригинальному коду MATLAB и что никакие ошибки времени выполнения не происходят. По умолчанию codegen генерирует MEX-функцию под названием readfile_mex в текущей папке. Это позволяет вам тестировать код MATLAB и MEX-функцию и сравнивать результаты.

Запустите MEX-функцию

Вызовите сгенерированную MEX-функцию и отобразите размер возвращаемой строки и ее первых 100 символов.

y = readfile_mex('readfile.m');
size(y)
ans = 1×2

           1        1857

y(1:100)
ans = 
    '% y = readfile(filename)
     % Read file 'filename' and return a MATLAB string with the contents
     % of th'

Сгенерируйте код С

codegen -config:lib readfile

Используя codegen с заданным -config cfg опция производит автономную библиотеку C.

Осмотрите сгенерированный код

По умолчанию код, сгенерированный для библиотеки, находится в папке codegen/lib/readfile/.

Файлы:

dir codegen/lib/readfile/
.                      readfile.c             readfile_initialize.o  
..                     readfile.h             readfile_ref.rsp       
buildInfo.mat          readfile.o             readfile_rtw.mk        
codeInfo.mat           readfile_data.c        readfile_rtwutil.c     
codedescriptor.dmr     readfile_data.h        readfile_rtwutil.h     
examples               readfile_data.o        readfile_rtwutil.o     
fclose.c               readfile_emxAPI.c      readfile_terminate.c   
fclose.h               readfile_emxAPI.h      readfile_terminate.h   
fclose.o               readfile_emxAPI.o      readfile_terminate.o   
fileManager.c          readfile_emxutil.c     readfile_types.h       
fileManager.h          readfile_emxutil.h     rtw_proj.tmw           
fileManager.o          readfile_emxutil.o     rtwtypes.h             
interface              readfile_initialize.c  
readfile.a             readfile_initialize.h  

Осмотрите код С для функции readfile.c

type codegen/lib/readfile/readfile.c
/*
 * File: readfile.c
 *
 * MATLAB Coder version            : 4.2
 * C/C++ source code generated on  : 21-Feb-2019 17:59:28
 */

/* Include Files */
#include <string.h>
#include "readfile.h"
#include "readfile_emxutil.h"
#include "fclose.h"
#include "fileManager.h"
#include "readfile_rtwutil.h"
#include <stdio.h>

/* Type Definitions */

/* Function Definitions */

/*
 * Put class and size constraints on function input.
 * Arguments    : const char filename_data[]
 *                const int filename_size[2]
 *                emxArray_char_T *y
 * Return Type  : void
 */
void readfile(const char filename_data[], const int filename_size[2],
              emxArray_char_T *y)
{
  signed char fileid;
  int wherefrom;
  FILE * filestar;
  long position_t;
  double position;
  int i0;
  unsigned char buffer[65536];
  int remaining;
  int b_index;
  emxArray_uint8_T *A;
  boolean_T exitg1;
  int other2Read;
  size_t nBytes;
  int numRead;
  int bytesOut;
  short bdims_idx_0;
  int buf_size_idx_0;
  int num2Read;
  size_t numReadSizeT;
  char buf_data[1024];

  /*  y = readfile(filename) */
  /*  Read file 'filename' and return a MATLAB string with the contents */
  /*  of the file. */
  /*  Call fopen(filename 'r'), but we need to convert the MATLAB */
  /*  string into a C type string (which is the same string with the */
  /*  NUL (\0) string terminator). */
  fileid = cfopen(filename_data, filename_size, "rb");

  /*  Call fseek(f, 0, SEEK_END) to set file position to the end of */
  /*  the file. */
  wherefrom = SEEK_END;
  filestar = fileManager(fileid);
  if ((fileid != 0) && (fileid != 1) && (fileid != 2)) {
  } else {
    filestar = NULL;
  }

  if (!(filestar == NULL)) {
    fseek(filestar, (long int)0.0, wherefrom);
  }

  /*  Call ftell(f) which will return the length of the file in bytes */
  /*  (as current file position is at the end of the file). */
  filestar = fileManager(fileid);
  if ((fileid != 0) && (fileid != 1) && (fileid != 2)) {
  } else {
    filestar = NULL;
  }

  if (filestar == NULL) {
    position = -1.0;
  } else {
    position_t = ftell(filestar);
    position = (double)position_t;
  }

  position = rt_roundd_snf(position);
  if (position < 2.147483648E+9) {
    if (position >= -2.147483648E+9) {
      i0 = (int)position;
    } else {
      i0 = MIN_int32_T;
    }
  } else if (position >= 2.147483648E+9) {
    i0 = MAX_int32_T;
  } else {
    i0 = 0;
  }

  /*  Reset current file position */
  wherefrom = SEEK_SET;
  filestar = fileManager(fileid);
  if ((fileid != 0) && (fileid != 1) && (fileid != 2)) {
  } else {
    filestar = NULL;
  }

  if (!(filestar == NULL)) {
    fseek(filestar, (long int)0.0, wherefrom);
  }

  /*  Initialize a buffer */
  memset(&buffer[0], 0, sizeof(unsigned char) << 16);

  /*  Remaining is the number of bytes to read (from the file) */
  remaining = i0;

  /*  Index is the current position to read into the buffer */
  b_index = 1;
  emxInit_uint8_T(&A, 1);
  exitg1 = false;
  while ((!exitg1) && (remaining > 0)) {
    /*  Buffer overflow? */
    if (b_index > MAX_int32_T - remaining) {
      other2Read = MAX_int32_T;
    } else {
      other2Read = remaining + b_index;
    }

    if (other2Read > 65536) {
      printf("Attempt to read file which is bigger than internal buffer.\n");
      fflush(stdout);
      printf("Current buffer size is %d bytes and file size is %d bytes.\n",
             65536, i0);
      fflush(stdout);
      exitg1 = true;
    } else {
      /*  Read as much as possible from the file into internal buffer */
      nBytes = sizeof(char);
      filestar = fileManager(fileid);
      if ((fileid != 0) && (fileid != 1) && (fileid != 2)) {
      } else {
        filestar = NULL;
      }

      if (filestar == NULL) {
        A->size[0] = 0;
        bytesOut = 0;
      } else {
        numRead = A->size[0];
        A->size[0] = remaining;
        emxEnsureCapacity_uint8_T(A, numRead);
        if (remaining > 1024) {
          bdims_idx_0 = 1024;
        } else {
          bdims_idx_0 = (short)remaining;
        }

        bytesOut = 0;
        numRead = 1;
        buf_size_idx_0 = bdims_idx_0;
        while ((bytesOut < remaining) && (numRead > 0)) {
          num2Read = buf_size_idx_0;
          other2Read = remaining - bytesOut;
          if (buf_size_idx_0 > other2Read) {
            num2Read = other2Read;
          }

          buf_size_idx_0 = bdims_idx_0;
          numRead = 0;
          other2Read = 1;
          while ((numRead < num2Read) && (other2Read > 0)) {
            numReadSizeT = fread(&buf_data[numRead], nBytes, num2Read - numRead,
                                 filestar);
            other2Read = (int)numReadSizeT;
            numRead += (int)numReadSizeT;
          }

          for (other2Read = 0; other2Read < numRead; other2Read++) {
            A->data[other2Read + bytesOut] = (unsigned char)buf_data[other2Read];
          }

          bytesOut += numRead;
        }

        numRead = bytesOut + 1;
        num2Read = A->size[0];
        for (other2Read = numRead; other2Read <= num2Read; other2Read++) {
          A->data[other2Read - 1] = 0U;
        }

        if (bytesOut < remaining) {
          if (1 > bytesOut) {
            A->size[0] = 0;
          } else {
            numRead = A->size[0];
            A->size[0] = bytesOut;
            emxEnsureCapacity_uint8_T(A, numRead);
          }
        }
      }

      position = (double)b_index + (double)bytesOut;
      if (position < 2.147483648E+9) {
        if (position >= -2.147483648E+9) {
          numRead = (int)position;
        } else {
          numRead = MIN_int32_T;
        }
      } else {
        numRead = MAX_int32_T;
      }

      numRead -= 2;
      if (b_index > numRead + 1) {
        num2Read = -1;
        numRead = -1;
      } else {
        num2Read = b_index - 2;
      }

      other2Read = numRead - num2Read;
      for (numRead = 0; numRead < other2Read; numRead++) {
        buffer[(num2Read + numRead) + 1] = A->data[numRead];
      }

      if (bytesOut == 0) {
        /*  Nothing more to read */
        exitg1 = true;
      } else {
        /*  Did something went wrong when reading? */
        if (bytesOut < 0) {
          printf("Could not read from file: %d.\n", bytesOut);
          fflush(stdout);
          exitg1 = true;
        } else {
          /*  Update state variables */
          remaining -= bytesOut;
          if ((b_index < 0) && (bytesOut < MIN_int32_T - b_index)) {
            b_index = MIN_int32_T;
          } else if ((b_index > 0) && (bytesOut > MAX_int32_T - b_index)) {
            b_index = MAX_int32_T;
          } else {
            b_index += bytesOut;
          }
        }
      }
    }
  }

  emxFree_uint8_T(&A);

  /*  Close file */
  b_fclose(fileid);
  i0 = y->size[0] * y->size[1];
  y->size[0] = 1;
  y->size[1] = b_index;
  emxEnsureCapacity_char_T(y, i0);
  for (i0 = 0; i0 < b_index; i0++) {
    y->data[i0] = (signed char)buffer[i0];
  }
}

/*
 * File trailer for readfile.c
 *
 * [EOF]
 */