外部データファイルを読み込んだり書き込んだり
- ◆プログラム作成ガイド
- ◆プログラムの開始
- ◆初期表示のデザイン
- ◆データの入力方法
- ◆クラスの作り方
- ◆データをメモリーに
- ◆ファイル読み書き
- ◆データの保存方法
- ◆ツリービューマウス右
- ◆画面表示インプリメント
- ◆複数のページ印字
- ◆DLL化する
- ◆エクセル似の入力
ここに紹介するプログラムは、WIN XP 2003/Windows 7 (32bits) - OS 環境でマイクロソフトのVisual Studio 2010 で作ったものです。
Windows XP/ Windows 7(32bits) での動作は確認済みですが…
ユーザ設定のデータは、外部にデータファイルとして保存する。
この機能により、ユーザ独自のカスタマイズした操作が出来る。
ユーザ独自に設定出来る機能を持たせることにより、カスタマイズされた動作がプログラムされます。
本プログラムでは、国名情報ファイル・壁熱貫流率データ・年間外気温度データをこの方法で外部ファイルとしました。
ファイルの作成・編集は、MFCのシリアライズ機能は使用せず独自のコードで処理しました。
これら外部ファイルは、自動的に、プログラムフォルダ下にDataフォルダを作り格納されるようにしました。
データは、保守がしやすいようにアスキー文字で書かれるようにしてあります。
新規作成・編集は専用のコードをプログラムしてありますが、標準のEditorでも読み込めます。
国情報ファイル
国情報ファイルは、プログラム起動と同時に表示されるCStartDlgクラスのイニシャライズ部分で読み込むようにしてあります。
プログラムが着目しているファイルフォルダがどこにあっても、Dataフォルダを読み込めるようなコードとした事が工夫です。
/////////////////////////////////////////////////////////////////////////////
// CStartDlg メッセージ ハンドラ
BOOL CStartDlg::OnInitDialog()
{
CDialog::OnInitDialog();
TCHAR szPath[MAX_PATH] = _T("");
CString szFile = _T("");
BOOL bRet;
GetModuleFileName( NULL, szPath, MAX_PATH ); //
プログラムデレクトリを取得
szFile = szPath;
szFile.TrimRight( _T( "AutoAC.exe" ));
szFile = szFile + _T( "Data" );
_chdir( szFile ); // カレントデレクトリをデータデレクトリに設定
CItems it;
bRet = it.CountryDataFileRead( "countrydata" );
if( bRet == TRUE )
GetCountryNames( &it );
else{
CCountryDlg dlg;
dlg.m_bCountry = FALSE;
dlg.DoModal();
it.CountryDataFileRead( "countrydata" );
GetCountryNames( &it );
}
return TRUE;
}
データファイルを読み込むルーチンは、SunApp.DLLにファイルオープンのルーチンは、HayFunc.DLLに書いてあります。
以下は、そのコードです(ファイルオープンのコードは省略します)。
ここで工夫したのは、ファイルを読み込む前の着目フォルダを保持して置き、ファイルを読み込んだ後に戻す事をしました。これにより、データフォルダを読み込む為、着目フォルダを強制的に変えても自動的に戻ります。
/////////////////////////////////////////
// CountryDataFile の読み込み
#include "ExFileControl.h"
#include "direct.h"
BOOL CItems::CountryDataFileRead(LPCTSTR fname)
{
CExFileControl fc;
CStdioFile file;
DWORD i, j;
TCHAR szOldPath[MAX_PATH]=_T("");
TCHAR szBuf[100]=_T("");
BOOL ret = FALSE;
_getcwd( szOldPath, MAX_PATH ); // カレントデレクトリを取得
if( ret = fc.OpenDataFileRead(fname, NULL, "cty", file ) != 0 ) {
j = file.GetLength()/65;
for( i = 0; i<j; i++ ) {
file.Read( szBuf, 63 );
m_ArrayCountryData.Add( szBuf );
file.Seek( 2, CFile::current ); // 改行文字のジャンプ
}
file.Close();
}
_chdir( szOldPath ); //
ファイルを読み込む前の着目フォルダに戻す
return ret;
}
//////////////////////////////////////////
// Country Data の文字列より必要なデータの切り出し
BOOL CItems::GetCountryData(CString data)
{
LPSTR str = new char[data.GetLength() + 1]; // CString を char に変換する
strcpy( str, data );
char* ctry = strtok( str, "," ); // 文字の切り出し(国名)
char* idod = strtok( NULL, "," ); // 文字の切り出し(緯度)
char* idof = strtok( NULL, "," ); // 文字の切り出し(緯度分)
char* keidod = strtok( NULL, "," ); // 文字の切り出し(経度)
char* keidof = strtok( NULL, "," ); // 文字の切り出し(経度分)
char* timediff = strtok( NULL, "," ); // 文字の切り出し(時間差)
char* oadb = strtok( NULL, "," );
char* oawb = strtok( NULL, "," );
char* zone = strtok( NULL, "," );
// ホワイトスペースを切り取る
m_country = strtok( ctry, " " );
m_idod = atoi( strtok(idod, " " ));
m_idof = atoi( strtok(idof, " " ));
m_keidod = atoi( strtok(keidod, " " ));
m_keidof = atoi( strtok(keidof, " " ));
m_timediff = atof( strtok(timediff, " " ));
m_oadb = atof( strtok(oadb, " " ));
m_oawb = atof( strtok(oawb, " " ));
m_zone = atoi( strtok(zone, " " ));
delete []str;
return 0;
}
壁熱貫流率データファイル
壁熱貫流率データは、CAutoACDocクラスのOnNewDocumentにコーディングしました。 従って、プログラム起動しスタートダイアログが表示されたすぐ後に読み込まれます。
BOOL CAutoACDoc::OnNewDocument()
{
// (SDI ドキュメントはこのドキュメントを再利用します。)
m_ArrayAircon.RemoveAll(); // 負荷計算データのリセット
m_Result.RemoveAll(); // 動的負荷計算データのリセット
m_ArrayList.RemoveAll();
CStartDlg dlg;
if( dlg.DoModal() == IDOK ) {
m_szPjname = dlg.m_strProject;
m_szPerform = dlg.m_strPerform;
m_it = dlg.m_it; // Country Data の読み込み
m_it.SetOaRh( atof(dlg.m_strRh ));
}
else{
return FALSE;
}
UpdateAllViews( NULL );
// ------- Wall Component の読み込み
CWallCompDlg Walldlg;
Walldlg.ReadCompData();
m_ArrayWallComp.Copy(
Walldlg.m_Array_WallComp ); 専用のアレー
// ------- デフォルトのファイル保存名設定
TCHAR szProject[100];
strcpy( szProject, m_szPjname );
SetTitle( szProject );
return TRUE;
}
プログラムが起動中、計算ファイルが変更されても壁熱貫流率ファイルが再利用できるように、専用のアレーにコピーされています。 更に、計算途中でも壁の熱貫流率ファイルを編集した場合、そのデータが即UpDateされるような工夫が必要です。
年間外気温度データファイル壁からの熱貫流負荷計算には、相当温度差が必要になります。
太陽データは、国情報データよりその度に計算するようにしましたが、相当温度差は対象ポイントの年間外気温度データが必要になります。 このデータをすべて保持しておくのは、実際的ではないので外部データファイルとしてユーザが設定するようにしました。
プログラム上で負荷計算を行うと、以下のコードが呼ばれ、外気温度データファイルを読み込みます。
///////////////////////////////////////////////
//負荷計算 Sub Routine
BOOL CAutoACDoc::ACLoadCalcu_Sub(CAirconData *air, CTime t, OPERATE *op, int
mn, int level, int nIndex)
{
BOOL bRet = FALSE; // YearTemp Data が読めないとき
CDate* ymd = new CDate( 15, mn, t.GetYear()); // 各月は15日を計算する
m_it.SetAlt( level ); // 海抜の設定
CreateSunData( ymd, &m_it ); // 太陽データ計算
delete ymd;
CString strCountry = m_it.GetCountryName(); // 国名
bRet = TempDataFileRead( strCountry, mn );
//
相当温度差計算
if( bRet == FALSE ) { // YearTemp Data が読めないとき
UpdateAllViews( NULL );
return FALSE;
}
WallLoadCalcu( air, mn, op, nIndex ); // 壁の負荷計算
GlassLoadCalcu( air, mn, op, nIndex ); // 窓の負荷計算
return TRUE;
}
下のコードは、外気温度データファイルを読み込むルーチンです
//////////////////////////////////////////
// TempDataFile の読み込み
BOOL CAutoACDoc::TempDataFileRead( LPCTSTR fname, int mn )
{
CExFileControl fc;
TCHAR szBuf[100] = _T("");
CStdioFile file;
LPTSTR tok;
BOOL ret = TRUE;
ret = fc.OpenDataFileRead( fname, NULL, "dat", file );
if( ret == TRUE ) {
file.ReadString( szBuf, 72 ); //INDEX Data 文字列の読み込み(72文字)
m_szRemarks = strtok(szBuf, ",");
file.Seek( 74, CFile::begin ); //改行文字のジャンプ
file.Seek( 74*2*(mn - 1), CFile::current ); // 設定月へジャンプ
for( int i=0; i<=1; i++ ) { //12時間分のデータ読み込み
file.ReadString( szBuf, 72 );
tok = strtok( szBuf,"," );
int time = i * 12;
while( tok != NULL ) {
m_tdata[time][mn - 1] = atof( tok );
tok = strtok( NULL, "," );
time++;
}
file.Seek( 3, CFile::current ); // 改行文字のジャンプ
}
file.Close();
}
return ret;
}
カスタマイズしたデータを外部ファイルとして扱うと、ユーザ独自の設定が比較的簡単に出来ますが、スピードは遅くなります。
ページ先頭に戻る
最終更新日: 2020/02/04