Main Content

本页翻译不是最新的。点击此处可查看最新英文版本。

生成代码以读取文本文件

此示例说明如何从 MATLAB® 代码生成独立的 C 库,它使用函数 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 函数

使用 codegen 命令生成 MEX 函数。

codegen readfile
Code generation successful.

在生成 C 代码之前,应首先在 MATLAB 中测试 MEX 函数,以确保它在功能上等同于原始 MATLAB 代码,并且不会出现任何运行时错误。默认情况下,codegen 在当前文件夹中生成名为 readfile_mex 的 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'

生成 C 代码

codegen -config:lib readfile
Code generation successful.

codegen 与指定的 -config cfg 选项结合使用生成独立 C 库。

检查生成的代码

默认情况下,为库生成的代码位于文件夹 codegen/lib/readfile/ 中。

这些文件是:

dir codegen/lib/readfile/
.                      ..                     _clang-format          buildInfo.mat          codeInfo.mat           codedescriptor.dmr     compileInfo.mat        examples               fileManager.c          fileManager.h          fileManager.o          interface              readfile.a             readfile.c             readfile.h             readfile.o             readfile_data.c        readfile_data.h        readfile_data.o        readfile_emxAPI.c      readfile_emxAPI.h      readfile_emxAPI.o      readfile_emxutil.c     readfile_emxutil.h     readfile_emxutil.o     readfile_initialize.c  readfile_initialize.h  readfile_initialize.o  readfile_rtw.mk        readfile_terminate.c   readfile_terminate.h   readfile_terminate.o   readfile_types.h       rtw_proj.tmw           rtwtypes.h             

检查 readfile.c 函数的 C 代码

type codegen/lib/readfile/readfile.c
/*
 * File: readfile.c
 *
 * MATLAB Coder version            : 23.2
 * C/C++ source code generated on  : 03-Aug-2023 18:53:26
 */

/* Include Files */
#include "readfile.h"
#include "fileManager.h"
#include "readfile_data.h"
#include "readfile_emxutil.h"
#include "readfile_initialize.h"
#include "readfile_types.h"
#include <math.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>

/* Function Declarations */
static double rt_roundd_snf(double u);

/* Function Definitions */
/*
 * Arguments    : double u
 * Return Type  : double
 */
static double rt_roundd_snf(double u)
{
  double y;
  if (fabs(u) < 4.503599627370496E+15) {
    if (u >= 0.5) {
      y = floor(u + 0.5);
    } else if (u > -0.5) {
      y = u * 0.0;
    } else {
      y = ceil(u - 0.5);
    }
  } else {
    y = u;
  }
  return y;
}

/*
 * 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)
{
  FILE *filestar;
  int wherefrom;
  emxArray_uint8_T *At;
  double position;
  int b_index;
  int i;
  int i1;
  int numRead;
  int other2Read;
  int remaining;
  unsigned char buffer[65536];
  signed char fileid;
  unsigned char *At_data;
  char *y_data;
  boolean_T exitg1;
  if (!isInitialized_readfile) {
    readfile_initialize();
  }
  /*  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);
  /*  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)) {
    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)) {
    filestar = NULL;
  }
  if (filestar == NULL) {
    position = -1.0;
  } else {
    long position_t;
    position_t = ftell(filestar);
    position = (double)position_t;
  }
  position = rt_roundd_snf(position);
  if (position < 2.147483648E+9) {
    if (position >= -2.147483648E+9) {
      i = (int)position;
    } else {
      i = MIN_int32_T;
    }
  } else if (position >= 2.147483648E+9) {
    i = MAX_int32_T;
  } else {
    i = 0;
  }
  /*  Reset current file position */
  wherefrom = SEEK_SET;
  filestar = fileManager(fileid);
  if ((fileid == 0) || (fileid == 1) || (fileid == 2)) {
    filestar = NULL;
  }
  if (!(filestar == NULL)) {
    fseek(filestar, (long int)0.0, wherefrom);
  }
  /*  Initialize a buffer */
  memset(&buffer[0], 0, 65536U * sizeof(unsigned char));
  /*  Remaining is the number of bytes to read (from the file) */
  remaining = i;
  /*  Index is the current position to read into the buffer */
  b_index = 1;
  emxInit_uint8_T(&At);
  At_data = At->data;
  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, i);
      fflush(stdout);
      exitg1 = true;
    } else {
      size_t nBytes;
      int bytesOut;
      int dims_idx_0;
      boolean_T doEOF;
      /*  Read as much as possible from the file into internal buffer */
      if (remaining >= MAX_int32_T) {
        dims_idx_0 = 1024;
        doEOF = true;
      } else {
        dims_idx_0 = remaining;
        doEOF = false;
      }
      nBytes = sizeof(char);
      filestar = fileManager(fileid);
      if ((fileid == 0) || (fileid == 1) || (fileid == 2)) {
        filestar = NULL;
      }
      if (!doEOF) {
        if (filestar == NULL) {
          At->size[0] = 0;
          bytesOut = 0;
        } else {
          short bdims_idx_0;
          i1 = At->size[0];
          At->size[0] = remaining;
          emxEnsureCapacity_uint8_T(At, i1);
          At_data = At->data;
          if (dims_idx_0 > 1024) {
            bdims_idx_0 = 1024;
          } else {
            bdims_idx_0 = (short)dims_idx_0;
          }
          bytesOut = 0;
          numRead = 1;
          while ((bytesOut < dims_idx_0) && (numRead > 0)) {
            int c;
            char tbuf[1024];
            c = bdims_idx_0;
            other2Read = dims_idx_0 - bytesOut;
            if (bdims_idx_0 > other2Read) {
              c = other2Read;
            }
            numRead = 0;
            other2Read = 1;
            while ((numRead < c) && (other2Read > 0)) {
              size_t numReadSizeT;
              numReadSizeT = fread(&tbuf[numRead], nBytes,
                                   (size_t)(c - numRead), filestar);
              other2Read = (int)numReadSizeT;
              numRead += (int)numReadSizeT;
            }
            for (other2Read = 0; other2Read < numRead; other2Read++) {
              At_data[other2Read + bytesOut] = (unsigned char)tbuf[other2Read];
            }
            bytesOut += numRead;
          }
          i1 = bytesOut + 1;
          numRead = At->size[0];
          for (other2Read = i1; other2Read <= numRead; other2Read++) {
            At_data[other2Read - 1] = 0U;
          }
        }
      } else {
        At->size[0] = 0;
        if (filestar == NULL) {
          bytesOut = 0;
        } else {
          int c;
          c = 1;
          bytesOut = 0;
          while (c > 0) {
            char tbuf[1024];
            c = 0;
            numRead = 1;
            while ((c < 1024) && (numRead > 0)) {
              size_t numReadSizeT;
              numReadSizeT =
                  fread(&tbuf[c], nBytes, (size_t)(1024 - c), filestar);
              numRead = (int)numReadSizeT;
              c += (int)numReadSizeT;
            }
            if (c < 1) {
              other2Read = 0;
            } else {
              other2Read = c;
            }
            i1 = At->size[0];
            numRead = At->size[0];
            At->size[0] += other2Read;
            emxEnsureCapacity_uint8_T(At, numRead);
            At_data = At->data;
            for (numRead = 0; numRead < other2Read; numRead++) {
              At_data[i1 + numRead] = (unsigned char)tbuf[numRead];
            }
            bytesOut += c;
          }
        }
      }
      position = (double)b_index + (double)bytesOut;
      if (position < 2.147483648E+9) {
        if (position >= -2.147483648E+9) {
          i1 = (int)position;
        } else {
          i1 = MIN_int32_T;
        }
      } else {
        i1 = MAX_int32_T;
      }
      if (b_index > i1 - 1) {
        numRead = 0;
        i1 = 0;
      } else {
        numRead = b_index - 1;
        i1--;
      }
      other2Read = i1 - numRead;
      for (i1 = 0; i1 < other2Read; i1++) {
        buffer[numRead + i1] = At_data[i1];
      }
      if (bytesOut == 0) {
        /*  Nothing more to read */
        exitg1 = true;

        /*  Did something went wrong when reading? */
      } else 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(&At);
  /*  Close file */
  cfclose(fileid);
  i = y->size[0] * y->size[1];
  y->size[0] = 1;
  y->size[1] = b_index;
  emxEnsureCapacity_char_T(y, i);
  y_data = y->data;
  for (i = 0; i < b_index; i++) {
    y_data[i] = (signed char)buffer[i];
  }
}

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