テキスト ファイルを読み取るコードの生成
この例では、関数 fopen/fread/fclose を使用してディスクからファイルを読み取る MATLAB® コードからスタンドアロン C ライブラリを生成する方法を示します。
関数 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.
-config cfg
オプションを指定して codegen
を使用すると、スタンドアロン 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
/* * Prerelease License - for engineering feedback and testing purposes * only. Not for sale. * File: readfile.c * * MATLAB Coder version : 5.6 * C/C++ source code generated on : 30-Jan-2023 12:47:01 */ /* 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] */