【MQL5】FileWriteStruct関数について

MQL5リファレンス
スポンサーリンク
スポンサーリンク
  1. FileWriteStruct関数の働き・役割
  2. FileWriteStruct関数の引数について
  3. FileWriteStruct関数の戻り値について
  4. FileWriteStruct関数を使ったサンプルコード
  5. サンプルコード解説1:グローバル領域部分
    1. script_show_inputs
    2. inputパラメータ
    3. ファイル書き込みに関連するパラメータ
    4. ローソク足データを格納する構造体
  6. サンプルコード解説2:OnStart関数部分その1
    1. 現在のサーバー時刻を取得
    2. バッファのサイズを格納する変数を宣言
    3. 各種データを格納するバッファーの宣言
    4. 構造体配列の宣言
    5. エラーコードのリセット
  7. サンプルコード解説3:OnStart関数部分その2
    1. ローソク足の時間をコピー
    2. ローソク足の高値をコピー
    3. ローソク足の安値をコピー
    4. ローソク足の始値をコピー
    5. ローソク足の終値をコピー
  8. サンプルコード解説4:OnStart関数部分その3
    1. 時間データの配列のサイズを取得
    2. 構造体配列のサイズを変更
    3. 各ローソク足データを構造体配列に格納
    4. ファイルを開き、構造体配列を書き込む準備をする
  9. サンプルコード解説5:OnStart関数部分その4
    1. ファイルが正常に開けた場合の処理
    2. ファイルが開かれたことをエキスパートログに出力
    3. 書き込まれたバイト数をカウントする変数の準備
    4. 構造体配列をループしてファイルに書き込む
    5. 書き込まれたバイト数とファイル名をエキスパートログに出力
    6. 総バイト数の検証と結果の出力
    7. ファイルを閉じる
  10. サンプルコード解説6:OnStart関数部分その5
    1. ファイルが開けなかった場合の処理
    2. エラーメッセージをエキスパートログに出力

FileWriteStruct関数の働き・役割

FileWriteStruct関数は、構造体の内容をバイナリファイルに書き込むための関数です。この関数を使用することで、指定したファイルポインタの現在の位置から構造体の情報をそのままバイナリ形式で保存することができます。例えば、金融データをローソク足の形式で保存する場合、この関数を使って簡潔にファイルに書き出すことができます。

主に、データの構造が固定されている場合や、大量のデータを効率よく保存する必要がある場合に便利です。また、FileWriteStruct関数は、構造体の内容をそのまま保存するため、後で読み込みやすく、効率的なファイル操作が可能となります。

FileWriteStruct関数の引数について

uint  FileWriteStruct(
  int          file_handle,       // ファイルハンドル
  const void&  struct_object,    // 構造体インスタンスへのリンク
  int          size=-1           // 書かれるバイト数
  );

第1引数:file_handle
file_handleは、FileOpen関数から返されるファイルハンドルです。ファイルに対する読み書きを行う際に使用されます。

第2引数:struct_object
struct_objectは、書き込む構造体インスタンスへの参照です。この構造体には、文字列動的配列仮想関数を含めることはできません。

第3引数:size
sizeは、書き込むバイト数です。デフォルトでは-1が指定されており、この場合、構造体全体がファイルに書き込まれます。

FileWriteStruct関数の戻り値について

FileWriteStruct関数戻り値は、正常に書き込まれたバイト数です。この戻り値により、実際にどれだけのデータがファイルに書き込まれたかを確認することができます。関数が正常に動作した場合は、書き込まれたバイト数が返されますが、何らかのエラーが発生した場合は0が返されます。

書き込まれたバイト数に応じてファイルポインタも移動し、次回の書き込みはその位置から行われます。

FileWriteStruct関数を使ったサンプルコード

//--- スクリプトの起動時に入力パラメータのウィンドウを表示する
#property script_show_inputs

//--- 端末からデータを受け取るパラメータを定義
input string         InpSymbolName="EURUSD";           // 分析対象の通貨ペアを指定
input ENUM_TIMEFRAMES InpSymbolPeriod=PERIOD_H1;       // 分析対象の時間軸を指定
input datetime       InpDateStart=D'2013.01.01 00:00'; // コピーするデータの開始日を指定

//--- データをファイルに書き込むためのパラメータを定義
input string         InpFileName="EURUSD.txt";         // 書き込み対象のファイル名
input string         InpDirectoryName="Data";          // 保存先のディレクトリ名

//--- ローソク足データを格納するための構造体を定義
struct candlesticks
 {
  double            open;  // ローソク足の始値
  double            close; // ローソク足の終値
  double            high;  // ローソク足の高値
  double            low;   // ローソク足の安値
  datetime          date;  // ローソク足の日付
 };

//--- スクリプトプログラムのエントリーポイントとなる関数
void OnStart()
 {
  //--- 現在のサーバー時刻を取得
  datetime     date_finish=TimeCurrent();
  
  //--- バッファー(データを一時保存する配列)のサイズを格納する変数を宣言
  int          size;
  
  //--- 各種データ(時間、価格)を格納するバッファーを配列として宣言
  datetime     time_buff[];   // ローソク足の時間を格納する配列
  double       open_buff[];   // ローソク足の始値を格納する配列
  double       close_buff[];  // ローソク足の終値を格納する配列
  double       high_buff[];   // ローソク足の高値を格納する配列
  double       low_buff[];    // ローソク足の安値を格納する配列
  
  //--- 構造体の配列を宣言し、後でローソク足データを格納する
  candlesticks cand_buff[];
  
  //--- エラーコードをリセット
  ResetLastError();
  
  //--- 指定範囲内のローソク足の時間をコピー
  if(CopyTime(InpSymbolName,InpSymbolPeriod,InpDateStart,date_finish,time_buff)==-1)
    {
    //--- 時間データの取得に失敗した場合のエラーメッセージを出力
    PrintFormat("時間データの取得に失敗しました。エラーコード = %d",GetLastError());
    return;  // 処理を終了
    }
  
  //--- 指定範囲内のローソク足の高値をコピー
  if(CopyHigh(InpSymbolName,InpSymbolPeriod,InpDateStart,date_finish,high_buff)==-1)
    {
    //--- 高値データの取得に失敗した場合のエラーメッセージを出力
    PrintFormat("高値データの取得に失敗しました。エラーコード = %d",GetLastError());
    return;  // 処理を終了
    }
  
  //--- 指定範囲内のローソク足の安値をコピー
  if(CopyLow(InpSymbolName,InpSymbolPeriod,InpDateStart,date_finish,low_buff)==-1)
    {
    //--- 安値データの取得に失敗した場合のエラーメッセージを出力
    PrintFormat("安値データの取得に失敗しました。エラーコード = %d",GetLastError());
    return;  // 処理を終了
    }
  
  //--- 指定範囲内のローソク足の始値をコピー
  if(CopyOpen(InpSymbolName,InpSymbolPeriod,InpDateStart,date_finish,open_buff)==-1)
    {
    //--- 始値データの取得に失敗した場合のエラーメッセージを出力
    PrintFormat("始値データの取得に失敗しました。エラーコード = %d",GetLastError());
    return;  // 処理を終了
    }
  
  //--- 指定範囲内のローソク足の終値をコピー
  if(CopyClose(InpSymbolName,InpSymbolPeriod,InpDateStart,date_finish,close_buff)==-1)
    {
    //--- 終値データの取得に失敗した場合のエラーメッセージを出力
    PrintFormat("終値データの取得に失敗しました。エラーコード = %d",GetLastError());
    return;  // 処理を終了
    }

  //--- 時間データの配列のサイズを取得
  size=ArraySize(time_buff);
  
  //--- 構造体の配列のサイズを変更し、ローソク足データを保存できるようにする
  ArrayResize(cand_buff,size);
  
  //--- 各ローソク足データを構造体配列に格納
  for(int i=0;i<size;i++)
    {
     cand_buff[i].open=open_buff[i];     // 始値を構造体に格納
     cand_buff[i].close=close_buff[i];   // 終値を構造体に格納
     cand_buff[i].high=high_buff[i];     // 高値を構造体に格納
     cand_buff[i].low=low_buff[i];       // 安値を構造体に格納
     cand_buff[i].date=time_buff[i];     // 時間データを構造体に格納
    }
 
  //--- ファイルを開き、構造体配列を書き込む準備をする(ファイルが存在しない場合は自動で作成)
  ResetLastError();
  int file_handle=FileOpen(InpDirectoryName+"//"+InpFileName,FILE_READ|FILE_WRITE|FILE_BIN|FILE_COMMON);
  
  //--- ファイルが正常に開けた場合の処理
  if(file_handle!=INVALID_HANDLE)
    {
    //--- ファイルが正常に開かれたことをエキスパートログに出力
    PrintFormat("%s ファイルが書き込み用に開かれました",InpFileName);
    PrintFormat("ファイルパス: %s\\Files\\",TerminalInfoString(TERMINAL_COMMONDATA_PATH));
    
    //--- 書き込まれたバイト数をカウントするための変数を準備
    uint counter=0;
    
    //--- 構造体配列をループし、各データをファイルに書き込む
    for(int i=0;i<size;i++)
        counter+=FileWriteStruct(file_handle,cand_buff[i]);  // 各ローソク足のデータをバイナリファイルに書き込む
    
    //--- 書き込まれたバイト数とファイル名をエキスパートログに出力
    PrintFormat("%d バイトの情報が %s ファイルに書き込まれました",counter,InpFileName);
    
    //--- 総バイト数が正しいかを検証し、結果をエキスパートログに出力
    PrintFormat("合計バイト数: %d * %d * %d = %d, %s",size,5,8,size*5*8,size*5*8==counter ? "正しい" : "エラー");
    
    //--- ファイルを閉じる
    FileClose(file_handle);
    PrintFormat("データが書き込まれ、%s ファイルは閉じられました",InpFileName);
    }
  else
    {
    //--- ファイルが開けなかった場合のエラーメッセージを出力
    PrintFormat("%s ファイルを開けませんでした。エラーコード = %d",InpFileName,GetLastError());
    }
 }

サンプルコード解説1:グローバル領域部分

//--- スクリプトの起動時に入力パラメータのウィンドウを表示する
#property script_show_inputs

//--- 端末からデータを受け取るパラメータを定義
input string         InpSymbolName="EURUSD";           // 分析対象の通貨ペアを指定
input ENUM_TIMEFRAMES InpSymbolPeriod=PERIOD_H1;       // 分析対象の時間軸を指定
input datetime       InpDateStart=D'2013.01.01 00:00'; // コピーするデータの開始日を指定

//--- データをファイルに書き込むためのパラメータを定義
input string         InpFileName="EURUSD.txt";         // 書き込み対象のファイル名
input string         InpDirectoryName="Data";          // 保存先のディレクトリ名

//--- ローソク足データを格納するための構造体を定義
struct candlesticks
 {
  double            open;  // ローソク足の始値
  double            close; // ローソク足の終値
  double            high;  // ローソク足の高値
  double            low;   // ローソク足の安値
  datetime          date;  // ローソク足の日付
 };

このセクションでは、スクリプトのグローバル領域に定義されている要素について解説します。グローバル領域とは、プログラム全体で使用できる変数や設定が宣言される場所です。この部分の定義は、スクリプトの動作に必要な設定やデータの構造を事前に準備する役割を果たしています。

script_show_inputs

script_show_inputsは、スクリプトが実行される際に入力パラメータのウィンドウを自動的に表示する設定です。この設定により、ユーザーはスクリプトの起動時に、指定された入力パラメータを変更することができます。

inputパラメータ

次に、inputとして宣言された変数は、ユーザーがスクリプト実行時に変更できるパラメータです。ここでは以下のパラメータが定義されています。

  • InpSymbolName:分析対象の通貨ペアを指定するための文字列型のパラメータです。デフォルトで「EURUSD」が設定されています。
  • InpSymbolPeriod:分析対象の時間軸を指定するための時間軸を表す型のパラメータです。デフォルトでは1時間足が設定されています。
  • InpDateStart:データコピーの開始日を指定するための日時型のパラメータです。デフォルトで2013年1月1日が指定されています。

これらのパラメータは、ユーザーがスクリプト実行時に、分析する通貨ペアや時間軸、コピーするデータの開始日を調整できるようにしています。

ファイル書き込みに関連するパラメータ

  • InpFileName:データを書き込む際のファイル名を指定するための文字列型のパラメータです。デフォルトで「EURUSD.txt」となっています。
  • InpDirectoryName:データを保存するディレクトリ名を指定するための文字列型のパラメータです。デフォルトでは「Data」というディレクトリに保存されます。

これらのパラメータにより、スクリプトがどのファイルにどこでデータを書き込むかをユーザーが指定できるようになります。

ローソク足データを格納する構造体

candlesticks構造体は、ローソク足の各データ(始値、終値、高値、安値、日付)を格納するために定義されています。この構造体は、ファイルに保存するデータの単位となり、各フィールドにローソク足の情報を格納します。

  • open:ローソク足の始値を格納するための数値型のフィールドです。
  • close:ローソク足の終値を格納するための数値型のフィールドです。
  • high:ローソク足の高値を格納するための数値型のフィールドです。
  • low:ローソク足の安値を格納するための数値型のフィールドです。
  • date:ローソク足の日付を格納するための日時型のフィールドです。

この構造体を使って、ローソク足のデータを一括で管理し、後にファイルに書き込む処理を行います。


このグローバル領域では、スクリプトの動作に必要な入力パラメータとデータ構造が定義されています。これらの設定により、ユーザーが必要に応じてスクリプトの動作をカスタマイズできるようになっています。

サンプルコード解説2:OnStart関数部分その1

//--- スクリプトプログラムのエントリーポイントとなる関数
void OnStart()
 {
  //--- 現在のサーバー時刻を取得
  datetime     date_finish=TimeCurrent();
  
  //--- バッファー(データを一時保存する配列)のサイズを格納する変数を宣言
  int          size;
  
  //--- 各種データ(時間、価格)を格納するバッファーを配列として宣言
  datetime     time_buff[];   // ローソク足の時間を格納する配列
  double       open_buff[];   // ローソク足の始値を格納する配列
  double       close_buff[];  // ローソク足の終値を格納する配列
  double       high_buff[];   // ローソク足の高値を格納する配列
  double       low_buff[];    // ローソク足の安値を格納する配列
  
  //--- 構造体の配列を宣言し、後でローソク足データを格納する
  candlesticks cand_buff[];
  
  //--- エラーコードをリセット
  ResetLastError();

このセクションでは、スクリプトのメイン処理が行われるOnStart関数について解説します。OnStart関数は、スクリプトが実行されると自動的に呼び出される関数であり、ここでデータの取得や処理が行われます。

現在のサーバー時刻を取得

date_finishは、TimeCurrent関数を使って現在のサーバー時間を取得しています。この時刻は、スクリプトが動作する環境での最新の時刻情報を取得するために使用されます。この変数は、後ほどデータの範囲指定に利用されます。

バッファのサイズを格納する変数を宣言

sizeは、後で使用するバッファ(データを一時的に保存する配列)のサイズを格納するための変数です。データの配列のサイズを確定した後、この変数配列のサイズを代入します。スクリプト内で配列の大きさを動的に制御するために重要です。

各種データを格納するバッファーの宣言

以下の変数では、ローソク足データ(時間や価格)を一時的に保存するためのバッファ配列として宣言しています。

  • time_buff:ローソク足の時間データを格納する配列です。ローソク足ごとの時間情報が格納されます。
  • open_buff:ローソク足の始値を格納する配列です。各ローソク足の開始時の価格情報が入ります。
  • close_buff:ローソク足の終値を格納する配列です。各ローソク足の終了時の価格情報が入ります。
  • high_buff:ローソク足の高値を格納する配列です。各ローソク足の期間内での最高価格が入ります。
  • low_buff:ローソク足の安値を格納する配列です。各ローソク足の期間内での最低価格が入ります。

これらの配列は、指定された期間のローソク足のデータを一時的に保存し、後で構造体にまとめてファイルに書き込むために使います。

構造体配列の宣言

cand_buffは、ローソク足データを格納するための構造体配列です。各ローソク足データ(時間、始値、終値、高値、安値)を個別に保存するために、前述のバッファからデータを受け取り、この配列にまとめます。

エラーコードのリセット

ResetLastError関数では、スクリプト実行時に発生したエラーコードをリセットしています。これにより、エラー処理が適切に行われ、次にエラーが発生した際に正確なエラーコードを取得できるようになります。

サンプルコード解説3:OnStart関数部分その2

 //--- 指定範囲内のローソク足の時間をコピー
  if(CopyTime(InpSymbolName,InpSymbolPeriod,InpDateStart,date_finish,time_buff)==-1)
    {
    //--- 時間データの取得に失敗した場合のエラーメッセージを出力
    PrintFormat("時間データの取得に失敗しました。エラーコード = %d",GetLastError());
    return;  // 処理を終了
    }
  
  //--- 指定範囲内のローソク足の高値をコピー
  if(CopyHigh(InpSymbolName,InpSymbolPeriod,InpDateStart,date_finish,high_buff)==-1)
    {
    //--- 高値データの取得に失敗した場合のエラーメッセージを出力
    PrintFormat("高値データの取得に失敗しました。エラーコード = %d",GetLastError());
    return;  // 処理を終了
    }
  
  //--- 指定範囲内のローソク足の安値をコピー
  if(CopyLow(InpSymbolName,InpSymbolPeriod,InpDateStart,date_finish,low_buff)==-1)
    {
    //--- 安値データの取得に失敗した場合のエラーメッセージを出力
    PrintFormat("安値データの取得に失敗しました。エラーコード = %d",GetLastError());
    return;  // 処理を終了
    }
  
  //--- 指定範囲内のローソク足の始値をコピー
  if(CopyOpen(InpSymbolName,InpSymbolPeriod,InpDateStart,date_finish,open_buff)==-1)
    {
    //--- 始値データの取得に失敗した場合のエラーメッセージを出力
    PrintFormat("始値データの取得に失敗しました。エラーコード = %d",GetLastError());
    return;  // 処理を終了
    }
  
  //--- 指定範囲内のローソク足の終値をコピー
  if(CopyClose(InpSymbolName,InpSymbolPeriod,InpDateStart,date_finish,close_buff)==-1)
    {
    //--- 終値データの取得に失敗した場合のエラーメッセージを出力
    PrintFormat("終値データの取得に失敗しました。エラーコード = %d",GetLastError());
    return;  // 処理を終了
    }

このセクションでは、OnStart関数内でローソク足データを取得する部分について詳しく解説します。各種ローソク足データ(時間、高値、安値、始値、終値)を取得し、エラーチェックを行う処理が含まれています。

ローソク足の時間をコピー

CopyTime関数を使用して、指定した通貨ペア、時間軸、開始日から終了日までのローソク足の時間情報を取得し、time_buffという配列に格納しています。このデータは、ローソク足の時間軸に関する情報を後で処理するために使用されます。

もし、CopyTime関数が-1を返すと、データの取得に失敗したことになります。この場合、エラーメッセージをエキスパートログに出力し、処理を終了します。

ローソク足の高値をコピー

CopyHigh関数を使用して、指定範囲内のローソク足の高値を取得し、high_buffという配列に格納します。この高値は、各ローソク足期間内での最高価格を表します。

もし、CopyHigh関数が-1を返す場合、高値データの取得に失敗したことになり、エラーメッセージをエキスパートログに出力して処理を終了します。

ローソク足の安値をコピー

CopyLow関数を使用して、指定範囲内のローソク足の安値を取得し、low_buffという配列に格納します。この安値は、各ローソク足期間内での最低価格を表します。

もし、CopyLow関数が-1を返す場合、安値データの取得に失敗したことを意味し、エラーメッセージをエキスパートログに出力して処理を終了します。

ローソク足の始値をコピー

CopyOpen関数を使って、指定した範囲内のローソク足の始値を取得し、open_buffという配列に格納します。この始値は、各ローソク足期間の最初に取引された価格です。

始値データの取得に失敗すると、同様にエラーメッセージをエキスパートログに出力し、処理を終了します。

ローソク足の終値をコピー

CopyClose関数を使って、指定した範囲内のローソク足の終値を取得し、close_buffという配列に格納します。この終値は、各ローソク足期間の最後に取引された価格です。

CopyClose関数が-1を返した場合、終値データの取得に失敗したことを示し、エラーメッセージを出力して処理を終了します。


この部分では、ローソク足に必要なデータを取得し、それぞれの取得が失敗した場合にエラーハンドリングを行う仕組みが記述されています。取得するデータには、時間、高値、安値、始値、終値といった、ローソク足の基本的な要素が含まれています。

サンプルコード解説4:OnStart関数部分その3

//--- 時間データの配列のサイズを取得
  size=ArraySize(time_buff);
  
  //--- 構造体の配列のサイズを変更し、ローソク足データを保存できるようにする
  ArrayResize(cand_buff,size);
  
  //--- 各ローソク足データを構造体配列に格納
  for(int i=0;i<size;i++)
    {
     cand_buff[i].open=open_buff[i];     // 始値を構造体に格納
     cand_buff[i].close=close_buff[i];   // 終値を構造体に格納
     cand_buff[i].high=high_buff[i];     // 高値を構造体に格納
     cand_buff[i].low=low_buff[i];       // 安値を構造体に格納
     cand_buff[i].date=time_buff[i];     // 時間データを構造体に格納
    }
 
  //--- ファイルを開き、構造体配列を書き込む準備をする(ファイルが存在しない場合は自動で作成)
  ResetLastError();
  int file_handle=FileOpen(InpDirectoryName+"//"+InpFileName,FILE_READ|FILE_WRITE|FILE_BIN|FILE_COMMON);

このセクションでは、OnStart関数の中で取得したローソク足データを構造体に格納し、ファイルに書き込む準備を行う部分について解説します。

時間データの配列のサイズを取得

sizeは、time_buff配列のサイズを取得して代入されています。time_buffにはローソク足の時間データが格納されており、この配列のサイズは、取得したローソク足データの総数を意味します。size変数を使って、後の処理で配列のリサイズやループ処理を行います。

構造体配列のサイズを変更

ArrayResize関数を使用して、cand_buff配列のサイズをtime_buff配列のサイズに合わせて変更します。これにより、ローソク足データを保持する構造体配列が、取得したデータの数と同じサイズにリサイズされ、各ローソク足データを格納できる準備が整います。

各ローソク足データを構造体配列に格納

forループを使用して、open_buff、close_buff、high_buff、low_buff、time_buffの各配列に保存されたローソク足のデータを、cand_buffという構造体配列に順次格納しています。具体的には、次のように構造体の各フィールドに対応するデータが保存されます。

  • open_buffのデータが始値として構造体に格納されます。
  • close_buffのデータが終値として構造体に格納されます。
  • high_buffのデータが高値として構造体に格納されます。
  • low_buffのデータが安値として構造体に格納されます。
  • time_buffのデータがローソク足の日付として構造体に格納されます。

このループ処理により、すべてのローソク足データが1つの構造体配列にまとめられ、後のファイル書き込みの準備が完了します。

ファイルを開き、構造体配列を書き込む準備をする

ResetLastError関数を使ってエラーコードをリセットした後、FileOpen関数でファイルを開きます。ファイルが存在しない場合は自動的に作成され、読み書き可能なバイナリモードで開かれます。

ファイルのパスは、InpDirectoryNameとInpFileNameを組み合わせたものになります。このファイルに、先ほど作成した構造体配列のデータが書き込まれる準備が整います。


この部分では、取得したデータを構造体にまとめてからファイルに書き込む準備が行われています。配列のサイズを揃え、構造体にデータを格納し、ファイルを適切に開く手順が示されています。

サンプルコード解説5:OnStart関数部分その4

  //--- ファイルが正常に開けた場合の処理
  if(file_handle!=INVALID_HANDLE)
    {
    //--- ファイルが正常に開かれたことをエキスパートログに出力
    PrintFormat("%s ファイルが書き込み用に開かれました",InpFileName);
    PrintFormat("ファイルパス: %s\\Files\\",TerminalInfoString(TERMINAL_COMMONDATA_PATH));
    
    //--- 書き込まれたバイト数をカウントするための変数を準備
    uint counter=0;
    
    //--- 構造体配列をループし、各データをファイルに書き込む
    for(int i=0;i<size;i++)
        counter+=FileWriteStruct(file_handle,cand_buff[i]);  // 各ローソク足のデータをバイナリファイルに書き込む
    
    //--- 書き込まれたバイト数とファイル名をエキスパートログに出力
    PrintFormat("%d バイトの情報が %s ファイルに書き込まれました",counter,InpFileName);
    
    //--- 総バイト数が正しいかを検証し、結果をエキスパートログに出力
    PrintFormat("合計バイト数: %d * %d * %d = %d, %s",size,5,8,size*5*8,size*5*8==counter ? "正しい" : "エラー");
    
    //--- ファイルを閉じる
    FileClose(file_handle);
    PrintFormat("データが書き込まれ、%s ファイルは閉じられました",InpFileName);
    }

このセクションでは、ファイルにローソク足データを書き込む処理と、書き込みが完了した後の処理について解説します。

ファイルが正常に開けた場合の処理

file_handleが無効なハンドルではない(INVALID_HANDLEではない)場合、つまりファイルが正常に開かれた場合の処理が開始されます。この条件が満たされない場合は、処理がスキップされ、エラーメッセージが表示される仕組みになっています。

ファイルが開かれたことをエキスパートログに出力

PrintFormat関数を使って、ファイルが書き込み用に開かれたことをエキスパートログに記録します。また、ファイルのパス情報もエキスパートログに出力され、実際にどこにデータが保存されるかを確認できるようになっています。TerminalInfoString関数を使用して、ターミナルのデータパスが取得されています。

書き込まれたバイト数をカウントする変数の準備

uint型変数counterを用意し、書き込まれたバイト数をカウントします。この変数は、後の処理で構造体配列に格納されたデータを順次ファイルに書き込み、その書き込みバイト数を累積するために使用されます。

構造体配列をループしてファイルに書き込む

forループを使用して、cand_buffという構造体配列の各要素をファイルに書き込んでいます。FileWriteStruct関数を使って、各ローソク足データをバイナリファイルに順次書き込み、そのバイト数をcounterに加算しています。この処理により、ローソク足データがバイナリ形式でファイルに保存されます。

書き込まれたバイト数とファイル名をエキスパートログに出力

書き込みが完了したら、書き込まれたバイト数とファイル名をエキスパートログに出力します。これにより、どれだけのデータが書き込まれたのかを確認することができます。

総バイト数の検証と結果の出力

次に、実際に書き込まれたバイト数が、計算で予測される総バイト数と一致しているかを検証します。計算では、size(ローソク足データの数)に、5(データフィールドの数)と8(各フィールドのバイト数)を掛けて合計バイト数を算出します。この合計バイト数とcounterを比較し、一致していれば「正しい」、一致しなければ「エラー」という結果をエキスパートログに出力します。

ファイルを閉じる

最後に、FileClose関数で開かれていたファイルを閉じます。ファイルが正常に閉じられたこともエキスパートログに出力され、すべての処理が無事完了したことを確認できます。


この部分では、ローソク足データをファイルに書き込み、書き込み結果を検証してからファイルを閉じるまでの処理が行われています。書き込みが成功したかどうかの確認を含め、データの一貫性を保証するためのチェックが行われていることが重要です。

サンプルコード解説6:OnStart関数部分その5

  else
    {
    //--- ファイルが開けなかった場合のエラーメッセージを出力
    PrintFormat("%s ファイルを開けませんでした。エラーコード = %d",InpFileName,GetLastError());
    }
 }

このセクションでは、ファイルを正常に開くことができなかった場合のエラーハンドリングについて解説します。

ファイルが開けなかった場合の処理

elseブロックでは、ファイルが正常に開けなかった場合の処理が行われます。file_handleが無効なハンドルINVALID_HANDLE)であった場合、つまりファイルを開くことに失敗した場合に実行されます。

エラーメッセージをエキスパートログに出力

PrintFormat関数を使って、ファイルが開けなかったことをエキスパートログに出力します。出力されるメッセージには、開こうとしたファイル名(InpFileName)と、GetLastError関数によって取得されたエラーコードが含まれています。エラーコードは、何が原因でファイルを開けなかったかを調査するために重要です。

この処理により、ファイルが開けなかった場合でも、ユーザーはエキスパートログを確認することで問題の原因を特定し、適切な対処を行うことができます。


この部分では、ファイルを開く際にエラーが発生した場合の処理が記述されています。エラー時の詳細なメッセージ出力により、問題発生時のデバッグが容易になるよう配慮されています。

タイトルとURLをコピーしました