###困っていること
業務アプリの中で,下記機能があります。現状,ファイルサイズと受信データの合計サイズが1MB以上の場合,3.4.のときに,「fp == NULL」と処理を作っているせいか,3.4.で更新したファイル名が新規作成されず,3.5.で書き込みエラーになります。3.4.のように設計したのは,ファイルオープン判定時に「fp != NULL」とチェックするので,fclose()すれば,ポインタ(アドレス)もなくなると思っていました。どのように修正するのが適切でしょうか?どなたかご教授お願いします。
「現状」
ファイルサイズと受信データの合計サイズが1MB未満:1→2→3→3.1.→1に戻っての繰り返し
ファイルサイズと受信データの合計サイズが1MB以上:1→2→3→3.2→3.3.→3.4.→3.5→合計サイズが1MB未満に戻っての繰り返し。
「大まかなフロー」
0. データ受信
0. 受信データサイズの取得
0. ファイルサイズの最大値チェック
3.1.最大値未満の場合,受信データ書込み
3.2.最大値以上の場合,ファイルクローズ
3.3ファイル名の更新
3.4.ファイルポインタがない場合,更新したファイル名のオープン
3.5.受信データの書き込み
###調査して分かったこと
- リスト3.2.でファイルクローズ(fclose())しても,ファイルポインタ(アドレス)はNULLにならない(デバッガ機能のインスペクタで確認済み)。
→3.4の「ファイルポインタがない場合」という条件判断を取り除くのが適切なのでしょうか?
###機能
本アプリは,該当装置からデータを受信したら,ファイルへ書き込みます。ファイルの最大サイズは1MBです。ファイルサイズと受信(書込む)データの合計サイズが1MB超えている場合,ファイル番号を更新したファイルに受信(書込む)データを書込みます。
###メモリイメージ
fopen()後とfclose()後のメモリイメージは下記のようなイメージでよいのでしょうか?
###テストアプリの画面
「データ書込み(200ms)」チェックボックスにチェックをつけると,200msでファイルへデータを書込む。メモにエラーログを出力する。
###ソース
「main.cpp」
C++
1//--------------------------------------------------------------------------- 2 3#include <vcl.h> 4#pragma hdrstop 5 6#include "main.h" 7//--------------------------------------------------------------------------- 8#pragma package(smart_init) 9#pragma resource "*.dfm" 10TForm1 *Form1; 11const int ADDSIZE = 1400; // 追加データサイズ 12const int FILESIZE_MAX = 1048576; // 最大ファイルサイズ(1MB=1,048,576Bytes) 13const int RETRYCNT = 20; // ファイルオープンリトライ回数 14const int SLEEPTIME = 100; // スリープ時間(ms) 15//--------------------------------------------------------------------------- 16__fastcall TForm1::TForm1(TComponent* Owner) 17 : TForm(Owner) 18{ 19 // 書込みファイルインデックスの初期化 20 writeIndex = 1; 21 // 書込みパスの初期化 22 writePath = "C:\C++Builder\FILE\Win32\Debug\"; 23 24 Timer1->Enabled = false; 25} 26//--------------------------------------------------------------------------- 27// データ保存 28void TForm1::SaveData() 29{ 30 // 変数宣言 31 int file_size = 0; // ファイルサイズ 32 int add_size = 0; // 追加データサイズ 33 int write_size = 0; // 書込みデータサイズ 34 AnsiString writeFilePath; // 書込みパス(ファイル名含む) 35 int ans_i = 0; // 関数の戻り値 36 char ch[50] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 37 38 // 書込みパス(ファイル名含む)の設定 39 writeFilePath = writePath + "test_" + writeIndex + ".log"; 40 41 // ファイルオープンリトライ対策(20回) 42 for(int i=0; i<RETRYCNT; i++) 43 { 44 // ジャーナルファイルをオープン(a:追加書込み,b:バイナリモード) 45 FILE *fp = fopen( writeFilePath.c_str(), "a+b" ); 46 // オープン成功の場合 47 if( fp != NULL ) 48 { 49 fseek( fp, 0, SEEK_END ); // ファイル最後尾に移動 50 file_size = ftell( fp ); // ファイルサイズを取得 51 fseek( fp, 0, SEEK_SET ); // ファイル先頭に戻る 52 53 // 追加データサイズ(実際は可変だが,試験のために固定値) 54 add_size = ADDSIZE; 55 56 // ファイルサイズ゙が1MBを超えている場合(次のファイルにデータを保存) 57 if( FILESIZE_MAX < (file_size + add_size) ) 58 { 59 // ファイルを閉じる 60 fclose( fp ); 61 // ファイルポインタの解放 62 // freeだと下記例外メッセージが出る 63/* プロジェクト Project1.exeは例外クラス $ 64 C0000005(メッセージ'access violation at 0x5003982b: read of address 0x04020000')を送出しました。 65*/ 66// free( fp ); 67 68 // 書込みインデックスの更新 69 writeIndex++; 70 71 // 書込みパス(ファイル名含む)の設定 72 writeFilePath = writePath + "test_" + writeIndex + ".log"; 73 } 74 try 75 { 76 // ファイルがオープンしていない場合 77 if( fp == NULL ) 78 { 79 // ファイルを新規オープン 80 fp = fopen( writeFilePath.c_str(), "ab" ); 81 } 82 } 83 catch(...) 84 { 85 86 } 87 // 書込みデータサイズ 88 write_size = add_size; 89 try 90 { 91 // ファイルへデータを書き込み 92 ans_i = (int)fwrite( ch, (size_t)write_size, 1, fp ); 93 // 書込み失敗の場合 94 if( ans_i != 1 ) 95 { 96 // エラーログ出力 97 Memo1->Lines->Add("データ書き込みエラー データサイズ:" + IntToStr(write_size)); 98 } 99 } 100 catch(...) 101 { 102 // エラーログ出力 103 Memo1->Lines->Add("ファイルオープンエラー リトライ回数:" + IntToStr(i+1)); 104 } 105 // ファイルを閉じる 106 fclose( fp ); 107 108 break; 109 } 110 // オープン失敗の場合 111 else 112 { 113 // エラーログ出力 114 Memo1->Lines->Add("ファイルオープンエラー リトライ回数:" + IntToStr(i+1)); 115 // スリープ時間の設定 116 std::chrono::milliseconds duration( SLEEPTIME ); 117 // スリープ 118 std::this_thread::sleep_for( duration ); 119 120 continue; 121 } 122 } 123} 124//--------------------------------------------------------------------------- 125void __fastcall TForm1::Timer1Timer(TObject *Sender) 126{ 127 Timer1->Enabled = false; 128 129 // データ保存 130 SaveData(); 131 132 Timer1->Enabled = true; 133} 134//--------------------------------------------------------------------------- 135 136void __fastcall TForm1::CheckBox1Click(TObject *Sender) 137{ 138 Timer1->Enabled = true; 139} 140//--------------------------------------------------------------------------- 141
「main.h」
C++
1//--------------------------------------------------------------------------- 2 3#ifndef mainH 4#define mainH 5//--------------------------------------------------------------------------- 6#include <System.Classes.hpp> 7#include <Vcl.Controls.hpp> 8#include <Vcl.StdCtrls.hpp> 9#include <Vcl.Forms.hpp> 10#include <Vcl.ExtCtrls.hpp> 11#include <chrono> 12#include <thread> 13//--------------------------------------------------------------------------- 14class TForm1 : public TForm 15{ 16__published: // IDE で管理されるコンポーネント 17 TMemo *Memo1; 18 TTimer *Timer1; 19 TCheckBox *CheckBox1; 20 void __fastcall Timer1Timer(TObject *Sender); 21 void __fastcall CheckBox1Click(TObject *Sender); 22private: // ユーザー宣言 23public: // ユーザー宣言 24 __fastcall TForm1(TComponent* Owner); 25 void SaveData(); 26 AnsiString writePath; // 書込みファイルパス 27 int writeIndex; // 書込みファイルインデックス 28}; 29//--------------------------------------------------------------------------- 30extern PACKAGE TForm1 *Form1; 31//--------------------------------------------------------------------------- 32#endif
###開発環境
OS:Windows64bit
IDE:Embarcadero C++Builder 10.3.3
回答2件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2021/11/11 22:16
2021/11/12 09:02