MATLAB Coder

最新のリリースでは、このページがまだ翻訳されていません。 このページの最新版は英語でご覧になれます。

テキスト ファイルの読み取り

この例では、標準 C 関数 fopen/fread/fclose を使用してディスクからファイルを読み取る MATLAB コードからスタンドアロン C ライブラリを生成する方法を示します。これらの C 関数を呼び出すために、MATLAB コードは関数 'coder.ceval' を使用します。

必要条件

この例には必要条件はありません。

新規フォルダーの作成と関連ファイルのコピー

以下のコードは、現在の作業フォルダー (pwd) 内にフォルダーを作成します。この新規フォルダーには、この例に関連するファイルのみが含められます。現在のフォルダーに影響を与えたくない (またはこのフォルダーにファイルを生成できない) 場合は、作業フォルダーを変更する必要があります。

コマンドの実行: 新規フォルダーの作成と関連ファイルのコピー

coderdemo_setup('coderdemo_readfile');

関数 'readfile' について

関数 readfile.mreadfile.m は、入力としてファイル名 (またはパス) を取得し、ファイルの内容を含む文字列を返します。

type readfile
% y = readfile(filename)
% Read file 'filename' and return a MATLAB string with the contents
% of the file. Internally C functions fopen/fread are used to read
% data from the file.
function y = readfile(filename) %#codegen

% The 'fprintf' function will not be compiled and instead passed
% to the MATLAB runtime. If we choose to generate code for this example,
% all calls to extrinsic functions are automatically eliminated.
coder.extrinsic('fprintf');

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

% Define a new opaque variable 'f' which will be of type 'FILE *'
% in the generated C code initially with the value NULL.
f = coder.opaque('FILE *', 'NULL');

% 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 = coder.ceval('fopen', c_string(filename), c_string('r'));

% Call fseek(f, 0, SEEK_END) to set file position to the end of
% the file.
coder.ceval('fseek', f, int32(0), coder.opaque('int', 'SEEK_END'));

% We need to initialize the variable 'filelen' to the proper type
% as custom C functions are not analyzed.
filelen = int32(0);

% 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 = coder.ceval('ftell', f);

% Reset current file position
coder.ceval('fseek', f, int32(0), coder.opaque('int', 'SEEK_SET'));

% Initialize a buffer
buffer = zeros(1,65536,'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', size(buffer,2), filelen);
        break
    end
    % Read as much as possible from the file into internal buffer
    nread = coder.opaque('size_t');
    nread = coder.ceval('fread', coder.ref(buffer(index)), int32(1), remaining, f);
    n = int32(0);
    n = coder.ceval('(int)',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
coder.ceval('fclose', f);

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

% Create a NUL terminated C string given a MATLAB string
function y = c_string(s)
y = [s 0];

関数 'readfile'は次の関数を使用します。'coder.opaque'(生成したコードの中で変数を宣言するため)、'coder.extrinsic'(指定した関数のコードを生成せずに実行を MATLAB にディスパッチするように 'codegen' に対して指示するため)、'coder.ceval'(外部 C 関数を呼び出すため)

検定に使用する MEX 関数の生成

'codegen' コマンドを使って MEX 関数を生成します。

codegen readfile

C コードを生成する前に、MATLAB で MEX 関数をテストして、その関数が元の MATLAB コードと機能的に等価であることと実行時エラーが発生しないことを確認しなければなりません。既定の設定では、'codegen' は現在のフォルダーの中に 'readfile_mex' という名前の MEX 関数を生成します。これにより、MATLAB コードと MEX 関数をテストして結果を比較することができます。

MEX 関数の実行

生成された MEX 関数を呼び出し、返された文字列のサイズと最初の 100 文字を表示します。

y = readfile_mex('readfile.m');
size(y)
y(1:100)
ans =

           1        2719


ans =

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

C コードの生成

cfg = coder.config('lib');
cfg.CustomSourceCode = '#include <stdio.h>';
codegen -config cfg readfile

'-config cfg' オプションを指定して 'codegen' を使用し、STDIO 標準ヘッダー ファイルを使ってスタンドアロン C ライブラリを生成します。

生成されたコードの確認

既定の設定では、生成されたライブラリのコードは codegen/lib/readfile/ に保存されます。

ファイルは、以下のとおりです。

dir codegen/lib/readfile/
.                      readfile_emxAPI.h      readfile_types.h       
..                     readfile_emxAPI.o      rtGetInf.c             
buildInfo.mat          readfile_emxutil.c     rtGetInf.h             
char.c                 readfile_emxutil.h     rtGetInf.o             
char.h                 readfile_emxutil.o     rtGetNaN.c             
char.o                 readfile_initialize.c  rtGetNaN.h             
codeInfo.mat           readfile_initialize.h  rtGetNaN.o             
interface              readfile_initialize.o  rt_nonfinite.c         
readfile.a             readfile_ref.rsp       rt_nonfinite.h         
readfile.c             readfile_rtw.mk        rt_nonfinite.o         
readfile.h             readfile_terminate.c   rtw_proj.tmw           
readfile.o             readfile_terminate.h   rtwtypes.h             
readfile_emxAPI.c      readfile_terminate.o   

関数 'readfile.c' の C コードの確認

type codegen/lib/readfile/readfile.c
/*
 * File: readfile.c
 *
 * MATLAB Coder version            : 2.6
 * C/C++ source code generated on  : 10-Jan-2014 01:00:27
 */

/* Include files */
#include "rt_nonfinite.h"
#include "readfile.h"
#include "readfile_emxutil.h"
#include "char.h"

/* Custom Source Code */
#include <stdio.h>

/* Function Definitions */

/*
 * The 'fprintf' function will not be compiled and instead passed
 *  to the MATLAB runtime. If we choose to generate code for this example,
 *  all calls to extrinsic functions are automatically eliminated.
 * 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)
{
  int filelen;
  int n;
  char tmp_data[1025];
  char cv0[2];
  static const char cv1[2] = { 'r', '\x00' };

  FILE * f;
  unsigned char buffer[65536];
  int b_index;
  boolean_T exitg1;
  long i0;
  size_t nread;
  emxArray_uint8_T *b_buffer;

  /*  y = readfile(filename) */
  /*  Read file 'filename' and return a MATLAB string with the contents */
  /*  of the file. Internally C functions fopen/fread are used to read */
  /*  data from the file. */
  /*  Put class and size constraints on function input. */
  /*  Define a new opaque variable 'f' which will be of type 'FILE *' */
  /*  in the generated C code initially with the value NULL. */
  /*  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). */
  /*  Create a NUL terminated C string given a MATLAB string */
  filelen = filename_size[1];
  for (n = 0; n < filelen; n++) {
    tmp_data[n] = filename_data[filename_size[0] * n];
  }

  tmp_data[filename_size[1]] = '\x00';
  for (n = 0; n < 2; n++) {
    cv0[n] = cv1[n];
  }

  f = fopen(&tmp_data[0], cv0);

  /*  Call fseek(f, 0, SEEK_END) to set file position to the end of */
  /*  the file. */
  fseek(f, 0, SEEK_END);

  /*  We need to initialize the variable 'filelen' to the proper type */
  /*  as custom C functions are not analyzed. */
  /*  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 = ftell(f);

  /*  Reset current file position */
  fseek(f, 0, SEEK_SET);

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

  /*  Remaining is the number of bytes to read (from the file) */
  /*  Index is the current position to read into the buffer */
  b_index = 1;
  exitg1 = false;
  while ((!exitg1) && (filelen > 0)) {
    /*  Buffer overflow? */
    i0 = (long)filelen + b_index;
    if (i0 > 2147483647L) {
      i0 = 2147483647L;
    } else {
      if (i0 < -2147483648L) {
        i0 = -2147483648L;
      }
    }

    if ((int)i0 > 65536) {
      exitg1 = true;
    } else {
      /*  Read as much as possible from the file into internal buffer */
      nread = fread(&buffer[b_index - 1], 1, filelen, f);
      n = (int)(nread);
      if ((n == 0) || (n < 0)) {
        /*  Nothing more to read */
        exitg1 = true;
      } else {
        /*  Did something went wrong when reading? */
        /*  Update state variables */
        filelen -= n;
        i0 = (long)b_index + n;
        if (i0 > 2147483647L) {
          i0 = 2147483647L;
        } else {
          if (i0 < -2147483648L) {
            i0 = -2147483648L;
          }
        }

        b_index = (int)i0;
      }
    }
  }

  emxInit_uint8_T(&b_buffer, 2);

  /*  Close file */
  fclose(f);
  n = b_buffer->size[0] * b_buffer->size[1];
  b_buffer->size[0] = 1;
  b_buffer->size[1] = b_index;
  emxEnsureCapacity((emxArray__common *)b_buffer, n, (int)sizeof(unsigned char));
  for (n = 0; n < b_index; n++) {
    b_buffer->data[b_buffer->size[0] * n] = buffer[n];
  }

  b_char(b_buffer, y);
  emxFree_uint8_T(&b_buffer);
}

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

クリーンアップ

ファイルを削除して元のフォルダーに戻ります。

コマンドの実行: クリーンアップ

cleanup