質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
86.12%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

C++Builder

C++Builderは、C/C++を用いてアプリ開発できる統合開発環境 (IDE) 。DelphiのC++版です。コンポーネントによるビジュアル開発、高機能なコードエディターなどで生産性の高い開発ができます。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

解決済

fclose(fp)ではファイルポインタはNULLにならないのでしょうか?

dem0nmichik0
dem0nmichik0

総合スコア37

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

C++Builder

C++Builderは、C/C++を用いてアプリ開発できる統合開発環境 (IDE) 。DelphiのC++版です。コンポーネントによるビジュアル開発、高機能なコードエディターなどで生産性の高い開発ができます。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

2回答

0リアクション

0クリップ

1533閲覧

投稿2021/11/11 14:59

編集2021/11/11 17:44

###困っていること
業務アプリの中で,下記機能があります。現状,ファイルサイズと受信データの合計サイズが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++

//--------------------------------------------------------------------------- #include <vcl.h> #pragma hdrstop #include "main.h" //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm" TForm1 *Form1; const int ADDSIZE = 1400; // 追加データサイズ const int FILESIZE_MAX = 1048576; // 最大ファイルサイズ(1MB=1,048,576Bytes) const int RETRYCNT = 20; // ファイルオープンリトライ回数 const int SLEEPTIME = 100; // スリープ時間(ms) //--------------------------------------------------------------------------- __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { // 書込みファイルインデックスの初期化 writeIndex = 1; // 書込みパスの初期化 writePath = "C:\C++Builder\FILE\Win32\Debug\"; Timer1->Enabled = false; } //--------------------------------------------------------------------------- // データ保存 void TForm1::SaveData() { // 変数宣言 int file_size = 0; // ファイルサイズ int add_size = 0; // 追加データサイズ int write_size = 0; // 書込みデータサイズ AnsiString writeFilePath; // 書込みパス(ファイル名含む) int ans_i = 0; // 関数の戻り値 char ch[50] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; // 書込みパス(ファイル名含む)の設定 writeFilePath = writePath + "test_" + writeIndex + ".log"; // ファイルオープンリトライ対策(20回) for(int i=0; i<RETRYCNT; i++) { // ジャーナルファイルをオープン(a:追加書込み,b:バイナリモード) FILE *fp = fopen( writeFilePath.c_str(), "a+b" ); // オープン成功の場合 if( fp != NULL ) { fseek( fp, 0, SEEK_END ); // ファイル最後尾に移動 file_size = ftell( fp ); // ファイルサイズを取得 fseek( fp, 0, SEEK_SET ); // ファイル先頭に戻る // 追加データサイズ(実際は可変だが,試験のために固定値) add_size = ADDSIZE; // ファイルサイズ゙が1MBを超えている場合(次のファイルにデータを保存) if( FILESIZE_MAX < (file_size + add_size) ) { // ファイルを閉じる fclose( fp ); // ファイルポインタの解放 // freeだと下記例外メッセージが出る /* プロジェクト Project1.exeは例外クラス $ C0000005(メッセージ'access violation at 0x5003982b: read of address 0x04020000')を送出しました。 */ // free( fp ); // 書込みインデックスの更新 writeIndex++; // 書込みパス(ファイル名含む)の設定 writeFilePath = writePath + "test_" + writeIndex + ".log"; } try { // ファイルがオープンしていない場合 if( fp == NULL ) { // ファイルを新規オープン fp = fopen( writeFilePath.c_str(), "ab" ); } } catch(...) { } // 書込みデータサイズ write_size = add_size; try { // ファイルへデータを書き込み ans_i = (int)fwrite( ch, (size_t)write_size, 1, fp ); // 書込み失敗の場合 if( ans_i != 1 ) { // エラーログ出力 Memo1->Lines->Add("データ書き込みエラー データサイズ:" + IntToStr(write_size)); } } catch(...) { // エラーログ出力 Memo1->Lines->Add("ファイルオープンエラー リトライ回数:" + IntToStr(i+1)); } // ファイルを閉じる fclose( fp ); break; } // オープン失敗の場合 else { // エラーログ出力 Memo1->Lines->Add("ファイルオープンエラー リトライ回数:" + IntToStr(i+1)); // スリープ時間の設定 std::chrono::milliseconds duration( SLEEPTIME ); // スリープ std::this_thread::sleep_for( duration ); continue; } } } //--------------------------------------------------------------------------- void __fastcall TForm1::Timer1Timer(TObject *Sender) { Timer1->Enabled = false; // データ保存 SaveData(); Timer1->Enabled = true; } //--------------------------------------------------------------------------- void __fastcall TForm1::CheckBox1Click(TObject *Sender) { Timer1->Enabled = true; } //---------------------------------------------------------------------------

「main.h」

C++

//--------------------------------------------------------------------------- #ifndef mainH #define mainH //--------------------------------------------------------------------------- #include <System.Classes.hpp> #include <Vcl.Controls.hpp> #include <Vcl.StdCtrls.hpp> #include <Vcl.Forms.hpp> #include <Vcl.ExtCtrls.hpp> #include <chrono> #include <thread> //--------------------------------------------------------------------------- class TForm1 : public TForm { __published: // IDE で管理されるコンポーネント TMemo *Memo1; TTimer *Timer1; TCheckBox *CheckBox1; void __fastcall Timer1Timer(TObject *Sender); void __fastcall CheckBox1Click(TObject *Sender); private: // ユーザー宣言 public: // ユーザー宣言 __fastcall TForm1(TComponent* Owner); void SaveData(); AnsiString writePath; // 書込みファイルパス int writeIndex; // 書込みファイルインデックス }; //--------------------------------------------------------------------------- extern PACKAGE TForm1 *Form1; //--------------------------------------------------------------------------- #endif

###開発環境
OS:Windows64bit
IDE:Embarcadero C++Builder 10.3.3

以下のような質問にはリアクションをつけましょう

  • 質問内容が明確
  • 自分も答えを知りたい
  • 質問者以外のユーザにも役立つ

リアクションが多い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

気になる質問をクリップする

クリップした質問は、後からいつでもマイページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

下記のような質問は推奨されていません。

  • 間違っている
  • 質問になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

適切な質問に修正を依頼しましょう。

まだ回答がついていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
86.12%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問

同じタグがついた質問を見る

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

C++Builder

C++Builderは、C/C++を用いてアプリ開発できる統合開発環境 (IDE) 。DelphiのC++版です。コンポーネントによるビジュアル開発、高機能なコードエディターなどで生産性の高い開発ができます。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。