[MFC]ファイルを閉じる機能を実装する

MFC
この記事は約5分で読めます。

既存のファイルのオープンを実装したので、今度は閉じる機能を実装します。

まだ一部変えたいところはありますが、一応動くようになったので記事にして公開します。

さて、ファイルを閉じる機能を実装するので、今回から個々の関数でいちいちファイルを開いて閉じるのではなく、CFileStdioクラスのメンバを持つようにして、ファイルを開く・閉じる処理でオープンとクローズをしたいと思います。

そのため、まずCMyEditorDlg.hでCFileStdioクラスのメンバを定義します。

// CMyEditorDlg ダイアログ
class CMyEditorDlg : public CDialogEx
{
//   ・・・省略・・・
public:
	CStdioFile m_file;
//   ・・・省略・・・
}

先頭につけているのはメンバのmです。これからは現在オープン中のファイルはこのメンバで管理することにします。

そのためOnMSave()とOnMOpenfile()でそれぞれ新たに開いていた処理を変更します。下に載せたのはOnMOpenfile()の例です。

void CMyEditorDlg::OnMOpenfile()
{
	// TODO: ここにコマンド ハンドラー コードを追加します。
//	CStdioFile	file;
	CString		ss;
	CString		ssall;
	long		mode;
	char		c[256];

	mode = CFile::modeCreate | CFile::modeNoTruncate | CFile::modeReadWrite | CFile::typeText;

	// すでに開いているファイルがあったら閉じる
	if (m_file.m_hFile != CFile::hFileNull)
	{
		m_file.Close();
	}

	if (m_file.Open(TEXT("C:\\temp\\test.txt"), mode))
	{
		while (m_file.ReadString(c,256))
		{
			ss = c;
			ssall = ssall + ss;
		}

		m_edit.SetWindowText(ssall);

//		file.Close();
}

CStdioFile クラスの宣言をやめて、ファイルを扱っていたところはm_fileメンバに変更しました。またファイルのClose()をしないようにしました。

ファイルの内容はエディットコントロールにすべて読みこんでいるので、Close()しないでも内容は一応持って置けるのですが、ファイルの編集を排他にしたいこともあってOpen()したままです。

次は順当に行けば OnMSave()の修正に入るところですが、バグが有って苦労したので先にファイルを閉じる機能について説明したいと思います。

ファイルを閉じる機能はメニューから使用します。メニューに「ファイル閉じる」メニューを追加して、クリック時のイベントハンドラとしてOnMClose()を実装します。

void CMyEditorDlg::OnMClosefile()
{
	// TODO: ここにコマンド ハンドラー コードを追加します。
	if (m_file.m_hFile != CFile::hFileNull)
	{
		m_file.Close();
		m_edit.SetWindowText("");
	}
}

こちらは簡単ですね。ただファイルをクローズしているだけです。

一つポイントなのは、ファイルをクローズしたらエディットコントロールのテキストの内容をクリアしているところでしょうか?

空文字列をセットしてコントロールに何も表示されないようにしています。

さて最後に OnMSave() です。恥ずかしながらこの関数にはバグが潜在していました。

void CMyEditorDlg::OnMSave()
{
	// TODO: ここにコマンド ハンドラー コードを追加します。
//	CStdioFile	file;
	CString		ss;
	CString		filepath;
	long		mode;


	if (m_file.m_hFile != CFile::hFileNull)
	{
		// ファイルが有る場合
	}
	else
	{
		// ファイルがない場合は開く
		mode = CFile::modeCreate | CFile::modeNoTruncate | CFile::modeReadWrite | CFile::typeText;

		if (m_file.Open(TEXT("C:\\temp\\test.txt"), mode))
		{
		}
		else
		{
			// ファイルがなくて、ファイルを新規で開けなかったらreturnする。
			return;
		}
	}

	m_edit.GetWindowText(ss);

	// 今開いているファイルを一旦消す
	filepath = m_file.GetFilePath();
	m_file.Close();
	m_file.Remove(filepath);
	m_file.Flush();

	// ファイルを開き直す。
	mode = CFile::modeCreate | CFile::modeNoTruncate | CFile::modeReadWrite | CFile::typeText;
	m_file.Open(filepath,mode);

	// ファイルを保存する
	m_file.WriteString(ss);

//		file.Close();

}

ファイルはOnMOpenfile()で開くようにしたので、セーブのタイミングではまだファイルが開いていないことが考えられますので、ファイルのOpenチェックを行い未オープンなら開き直すようにしています。

その後の処理はすごい変えたいんですが、他に思いつかないのでとりあえずここまでで公開します。一度開いたファイルに文字を追加していく文にはいいんですが、ファイルの送料が短くなったときに、保存したい文字列と保存結果に差異が出てきてしまっていました。

これは保存する文字列よりも長い部分がファイルにゴミとして残っていてそれが消えないという状態のはずです。……が、ファイルをOpen時のサイズよりも小さくする方法がわかりませんでした。

そのためもう消しちゃっています。セーブする前に今開いているファイルのパスだけ覚えておいてクリアして、その後ファイルを新規作成してエディットコントロールの文字列を再設定しています。

これよりも良い処理があるよって方がいましたらコメントくださると助かります。

コメント

  1. […] […]

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