MFCの基礎 - ファイル
ファイルを開く
CFile
クラスのOpen
メソッドは、第1引数はファイル名、第2引数はファイルモードを指定する。
CFile File;
if(File.Open(_T("test.dat"), CFile::modeCreate| CFile::modeNoTruncate | CFile::modeWrite | CFile::typeBinary))
{
// To do something
}
file.Close();
主なモードを以下に記載する。
モード名 | 説明 |
---|---|
CFile::modeCreate | ファイルを新規に作成する。 既にファイルがある場合は、削除して新規に作成する。 |
CFile::modeNoTruncate | modeCreateと組み合わせて使用する場合、 既にファイルがある場合は新規作成せずに開く。 |
CFile::modeRead | ファイルを読み取り専用で開く。 |
CFile::modeReadWrite | ファイルを読み書き可能で開く。 |
CFile::modeWrite | ファイルを書き込み専用で開く。 |
CFile::shareDenyNone | 他プロセスからも読み書きできる状態でファイルを開く。 |
CFile::shareExclusive | ファイルを排他モードで開く。 |
CFile::typeText | テキストモードを設定する。 派生クラスで使用する。 |
CFile::typeBinary | バイナリモードを設定する。 派生クラスで使用する。 |
1行ずつ読み込む
CStdioFile File(_T("test.dat"), CFile::modeCreate| CFile::modeNoTruncate | CFile::modeRead | CFile::typeText);
CString strReadLine = _T("");
while(File.ReadString(strReadLine))
{
TRACE(strReadLine + _T("\n"));
}
ファイルに書き込む
CStdioFile File(_T("test.dat"), CFile::modeCreate| CFile::modeNoTruncate | CFile::modeWrite | CFile::typeText);
CString strWriteLine1 = _T("hoge\n");
File.WriteString(strWriteLine1);
CString strWriteLine2 = _T("piyo\n");
File.WriteString(strWriteLine2);
File.Close();
ファイルに追記する
CFileおよびCStdioFileには追記モードが存在しないので、ファイルを開いた後、書き込み位置を指定する必要がある。 下記のサンプルコードでは、ファイルを書き込みモードで開いた後、SeekToEndメソッドで書き込み位置を最後尾に移動する。
CStdioFile File(_T("test.dat"), CFile::modeCreate| CFile::modeNoTruncate | CFile::modeWrite | CFile::typeText);
File.SeekToEnd(); // 書き込み位置を最後尾に移動
CString strWriteLine1 = _T("hoge\n");
File.WriteString(strWriteLine1); // Write a line
CString strWriteLine2 = _T("piyo\n");
File.WriteString(strWriteLine2); // Write a line
File.Close();
ファイルを削除する
// 単一のファイルを削除する
CFile::Remove(_T("C:\\test.txt")); // Cドライブ直下のtest.txtファイルを削除する
// 複数のファイルやディレクトリを削除する
CString strRemoveDirPath = _T("C:\\test?");
strRemoveDirPath.SetAt(strRemoveDirPath.GetLength() - 1, 0);
SHFILEOPSTRUCT drive = {};
drive.hwnd = this->m_hWnd; // ウィンドウハンドル
drive.wFunc = FO_DELETE; // 実行する操作
drive.pFrom = strRemoveDirPath; // 対象ファイル名
drive.pTo = NULL; // 目的ファイル名
drive.fFlags = FOF_ALLOWUNDO; // フラグ
SHFileOperation(&drive);
wFuncは、下記に示す通り、実行する操作を指定する。
命令マクロ | 説明 |
---|---|
FO_MOVE | pFromをpToの位置に移動 |
FO_COPY | pFromをpToの位置にコピー |
FO_DELETE | Fromを削除 |
FO_RENAME | pFromをpToに変更 |
pFromにはディレクトリおよびファイルを指定する。ワイルドカードも使用できる。
また、NULL文字(\0)で区切ると複数指定できる。
fFlagは、下記に示す通り、動作時のフラグを指定する。
命令マクロ | 説明 |
---|---|
FOF_SILENT | 経過を表すダイアログボックス非表示 |
FOF_ALLOWUNDO | 削除の場合はゴミ箱に移動 |
FOF_NOERRORUI | エラーが発生した場合はUI非表示 |
FOF_NOCONFIRMATION | 表示されるダイアログボックスで『はい』または『すべて』を選択する |
ファイル / ディレクトリのコピー・移動・削除
// ファイルのコピー
BOOL CopyFile(
LPCTSTR lpExistingFileName, // コピー元のファイルのパス
LPCTSTR lpNewFileName, // コピー先のファイルのパス
BOOL bFailIfExists // 上書き許可 / 不許可
);
// ファイルの移動・ファイル名の変更
BOOL MoveFile(
LPCTSTR lpExistingFileName, // 移動元のファイルのパス
LPCTSTR lpNewFileName // 移動後のファイルのパス
);
// ファイルの削除
BOOL DeleteFile(
LPCTSTR lpFileName // 削除するファイルのパス
);
ファイル / ディレクトリの属性の取得・設定
// ファイルおよびディレクトリの属性の取得
DWORD GetFileAttributes(
LPCTSTR lpFileName // ファイルのパス
);
// ファイルおよびディレクトリの属性の設定
BOOL SetFileAttributes(
LPCTSTR lpFileName, // ファイルのパス
DWORD dwAttributes // 属性フラグ
);
定数 | 意味 |
---|---|
FILE_ATTRIBUTE_NORMAL | 特に属性なし |
FILE_ATTRIBUTE_ARCHIVE | アーカイブ属性 |
FILE_ATTRIBUTE_READONLY | 読み取り専用の属性 |
FILE_ATTRIBUTE_HIDDEN | 隠しファイルの属性 |
FILE_ATTRIBUTE_SYSTEM | システムファイルの属性 |
FILE_ATTRIBUTE_DIRECTORY | ディレクトリの属性 |
FILE_ATTRIBUTE_NORMAL
属性は、他の属性定数と組み合わせて使用できない。
FILE_ATTRIBUTE_DIRECTORY
属性は、属性を指定しても設定できない。
ファイルのタイプの取得
DWORD GetFileType(
HANDLE hFile // ファイルのハンドル
);
以下の例では、変数hFileにファイルのハンドルを指定する。
GetFileType
関数を使用して、コンソールの標準入出力等でリダイレクションされたかどうかを確認することができる。
// ファイルのタイプの判定
switch(GetFileType(hFile))
{
CASE FILE_TYPE_UNKNOWN:
printf(TEXT("ファイルのタイプは不明\n"));
break;
CASE FILE_TYPE_DISK:
printf(TEXT("ファイルのタイプはディスク上のファイル\n"));
break;
CASE FILE_TYPE_CHAR:
printf(TEXT("ファイルのタイプはデバイスまたはコンソール\n"));
break;
CASE FILE_TYPE_PIPE:
printf(TEXT("ファイルのタイプは名前付きまたは名前なしパイプ\n"));
break;
DEFAULT:
printf(TEXT("GetFileType関数の致命的なエラー\n"));
break;
}
定数 | 意味 |
---|---|
FILE_TYPE_UNKNOWN | ファイルのタイプは不明 |
FILE_TYPE_DISK | ファイルのタイプはディスク上のファイル |
FILE_TYPE_CHAR | ファイルのタイプはデバイスまたはコンソール |
FILE_TYPE_PIPE | ファイルのタイプは、名前付きパイプまたは名前なしパイプ |
ファイルサイズの取得
GetFileSize関数
DWORD GetFileSize(
HANDLE hFile, // ファイルのハンドル
LPDWORD lpFileSizeHigh // ファイルサイズの上位ワード
);
以下の例では、変数hFileにファイルのハンドルを指定して、
4[GB]以下のファイルの場合、GetFileSize関数の戻り値をそのまま受け取り、4[GB]以上のファイルの場合、上位ワードのポインタを第2引数に渡している。
その後、64ビット整数の変数等に代入して使用する。
// 4[GB]以下のファイルサイズの取得
DWORD dwSize = GetFileSize(hFile, NULL);
// 4[GB]以上のファイルサイズの取得
DWORDLONG dllSize = 0; // 64ビット整数
DWORD dwSize = 0; // 下位ワード
DWORD dwHigh = 0; // 上位ワード
dwSize = GetFileSize(hFile, &dwHigh);
dllSize = (((DWORDLONG)dwHigh << 32) | dwSize);
GetFileSizeEx関数
4[GB]以上のファイルサイズを取得する場合、GetFileSizeEx
関数も使用できる。
BOOL GetFileSizeEx(
HANDLE hFile, // ファイルのハンドル
LPLARGE_INTEGER lpFileSize // ファイルサイズの構造体
);
LARGE_INTEGER構造体を、以下に示す。
typedef union _LARGE_INTEGER {
struct {
DWORD LowPart; // 下位32ビット
LONG HighPart; // 上位32ビット
};
struct {
DWORD LowPart; // 下位32ビット
LONG HighPart; // 上位32ビット
} u;
LONGLONG QuadPart; // 64ビット整数
} LARGE_INTEGER, *LPLARGE_INTEGER;
以下の例では、変数hFileにファイルのハンドルを指定して、ファイルサイズを64ビット整数で表示している。
また、printf
関数がC99規格に準じている場合は、%lld
を指定することで64ビット整数を表示できる。
LARGE_INTEGER i64Size = 0;
GetFileSizeEx(hFile, &i64Size);
printf(TEXT("ファイルサイズ : %I64ld\n"), i64Size.QuadPart);
// または
// printf(TEXT("ファイルサイズ : %lld\n"), i64Size.QuadPart);
ファイルが実行可能かどうか確認する
BOOL GetBinaryType(
LPCTSTR lpApplicationName, // ファイルのパス
LPDWORD lpBinaryType // バイナリタイプ情報
);
以下の例では、GetBinaryType
関数を使用して、ファイルが実行可能かどうかを確認している。
バッチファイル(*.bat)やDLLファイルは実行可能とは判定しない。
DWORD dwType = 0;
GetBinaryType(TEXT("C:\\Windows\\System32\\calc.exe"), &dwType);
switch(dwType)
{
case SCS_32BIT_BINARY:
printf(TEXT("Win32ベースのアプリケーション\n"));
break;
case SCS_DOS_BINARY:
printf(TEXT("MS-DOSベースのアプリケーション\n"));
break;
case SCS_OS216_BINARY:
printf(TEXT("16ビット版OS/2ベースのアプリケーション\n"));
break;
case SCS_PIF_BINARY:
printf(TEXT("MS-DOSベースのアプリケーションを実行するPIFファイル\n"));
break;
case SCS_POSIX_BINARY:
printf(TEXT("POSIXベースのアプリケーション\n"));
break;
case SCS_WOW_BINARY:
printf(TEXT("16ビット版Windowsベースのアプリケーション\n"));
break;
default:
printf(TEXT("GetFileType関数の致命的なエラー\n"));
break;
}
タイムスタンプの取得 / 設定
タイムスタンプの取得
この関数群は、ディレクトリも同様にタイムスタンプを取得できる。
// タイムスタンプの取得
BOOL GetFileTime(
HANDLE hFile, // ファイルのハンドル
LPFILETIME lpCreationTime, // 作成日時
LPFILETIME lpLastAccessTime, // 最終アクセス日時
LPFILETIME lpLastWriteTime // 最終更新日時
);
// タイムスタンプからローカル時間に変換
BOOL FileTimeToLocalFileTime(
CONST FILETIME* lpFileTime, // 世界標準時間のファイル時刻
LPFILETIME lpLocalFileTime // ローカル時間のファイル時刻
);
// タイムスタンプからシステム時間に変換
BOOL FileTimeToSystemTime(
CONST FILETIME* lpFileTime, // 変換前のファイル時刻
LPSYSTEMTIME lpSystemTime // 変換後のシステム日時
);
FILETIME
構造体およびSYSTEMTIME
構造体を、以下に示す。
typedef struct _FILETIME {
DWORD dwLowDateTime; // 下位32ビット
DWORD dwHighDateTime; // 上位32ビット
} FILETIME, *PFILETIME;
typedef struct _SYSTEMTIME {
WORD wYear; // 年(1901~)
WORD wMonth; // 月(1-12)
WORD wDayOfWeek; // 曜日(0-6)
WORD wDay; // 日(1-31)
WORD wHour; // 時(0-23)
WORD wMinute; // 分(0-59)
WORD wSecond; // 秒(0-59)
WORD wMilliseconds; // ミリ秒(0-999)
} SYSTEMTIME, *PSYSTEMTIME;
以下の例では、変数hFileにファイルのハンドルを指定して、タイムスタンプを取得している。
ディレクトリの場合は、FILE_FLAG_BACKUP_SEMANTICS
フラグを指定する。
FILETIME ft1, ft2, ft3; // ファイル時刻
FILETIME lt1, lt2, lt3; // ローカル時刻
SYSTEMTIME st1, st2, st3; // システム日時
// ファイル日時の取得
GetFileTime( hFile, &ft1, &ft2, &ft3 );
// ファイル時刻からローカル時刻に変換
FileTimeToLocalFileTime( &ft1, <1 ); // 作成日時
FileTimeToLocalFileTime( &ft2, <2 ); // 最終アクセス日時
FileTimeToLocalFileTime( &ft3, <3 ); // 最終更新日時
// ローカル時刻からシステム日時に変換
FileTimeToSystemTime( <1, &st1 ); // 作成日時
FileTimeToSystemTime( <2, &st2 ); // 最終アクセス日時
FileTimeToSystemTime( <3, &st3 ); // 最終更新日時
// 作成日時をprintf()で表示
printf(TEXT("%04d/%02d/%02d (%d) %02d:%02d:%02d.%03d\n"),
st1.wYear, // 年(1901-)
st1.wMonth, // 月(1-12)
st1.wDay, // 日(1-31)
st1.wDayOfWeek, // 曜日(0-6)
st1.wHour, // 時(0-23)
st1.wMinute, // 分(0-59)
st1.wSecond, // 秒(0-59)
st1.wMilliseconds // ミリ秒(0-999)
);
タイムスタンプの設定
この関数群は、ディレクトリも同様にタイムスタンプを設定できる。
// システム時間からファイル日時に変換
BOOL SetFileTime(
HANDLE hFile, // ファイルのハンドル
CONST FILETIME* lpCreationTime, // 作成日時
CONST FILETIME* lpLastAccessTime, // 最終アクセス日時
CONST FILETIME* lpLastWriteTime // 最終更新日時
);
// ローカル時間からファイル日時に変換
BOOL LocalFileTimeToFileTime(
CONST FILETIME* lpLocalFileTime, // ローカル時間のファイル時刻
LPFILETIME lpFileTime // 世界標準時間のファイル時刻
);
// ファイル日時の設定
BOOL SystemTimeToFileTime(
CONST SYSTEMTIME* lpSystemTime, // 変換前のシステム日時
LPFILETIME lpFileTime // 変換後のファイル時刻
);
FILETIME構造体およびSYSTEMTIME構造体を、以下に示す。
typedef struct _FILETIME {
DWORD dwLowDateTime; // 下位32ビット
DWORD dwHighDateTime; // 上位32ビット
} FILETIME, *PFILETIME;
typedef struct _SYSTEMTIME {
WORD wYear; // 年(1901~)
WORD wMonth; // 月(1-12)
WORD wDayOfWeek; // 曜日(0-6)
WORD wDay; // 日(1-31)
WORD wHour; // 時(0-23)
WORD wMinute; // 分(0-59)
WORD wSecond; // 秒(0-59)
WORD wMilliseconds; // ミリ秒(0-999)
} SYSTEMTIME, *PSYSTEMTIME;
以下の例では、変数hFileにファイルのハンドルを指定して、タイムスタンプを設定している。
ディレクトリの場合は、FILE_FLAG_BACKUP_SEMANTICS
フラグを指定する。
このフラグを指定しない場合、正常に処理できないことに注意する。
FILETIME ft1, ft2, ft3; // ファイル時刻
FILETIME lt1, lt2, lt3; // ローカル時刻
SYSTEMTIME st1, st2, st3; // システム日時
// 現在の日時を構造体にセット
GetLocalTime(&st1);
GetLocalTime(&st2);
GetLocalTime(&st3);
// システム日時からローカル時刻に変換
SystemTimeToFileTime(&st1, <1); // 作成日時
SystemTimeToFileTime(&st2, <2); // 最終アクセス日時
SystemTimeToFileTime(&st3, <3); // 最終更新日時
// ローカル時刻からファイル時刻に変換
LocalFileTimeToFileTime(<1, &ft1); // 作成日時
LocalFileTimeToFileTime(<2, &ft2); // 最終アクセス日時
LocalFileTimeToFileTime(<3, &ft3); // 最終更新日時
// ファイル日時の設定
SetFileTime(hFile, &ft1, &ft2, &ft3);
ファイル / ディレクトリの検索
// 最初のファイルを検索
HANDLE FindFirstFile(
LPCTSTR lpFileName, // ファイルのパス
LPWIN32_FIND_DATA lpFindFileData // データバッファ
);
// 次のファイルを検索
BOOL FindNextFile(
HANDLE hFindFile, // 検索ハンドル
LPWIN32_FIND_DATA lpFindFileData // データバッファ
);
// ファイル検索を終了する
BOOL FindClose(
HANDLE hFindFile // 検索ハンドル
);
LPWIN32_FIND_DATA構造体を以下に示す。
typedef struct _WIN32_FIND_DATA {
DWORD dwFileAttributes; // 属性
FILETIME ftCreationTime; // 作成日時
FILETIME ftLastAccessTime; // 最終アクセス日時
FILETIME ftLastWriteTime; // 最終更新日時
DWORD nFileSizeHigh; // サイズ(上位ワード)
DWORD nFileSizeLow; // サイズ(下位ワード)
DWORD dwReserved0; // 予約領域
DWORD dwReserved1; // 予約領域
TCHAR cFileName[ MAX_PATH ]; // ファイル名
TCHAR cAlternateFileName[ 14 ]; // 8.3形式のファイル名
} WIN32_FIND_DATA, *PWIN32_FIND_DATA;
以下の例では、WIN32_FIND_DATA
構造体のcFileName
メンバ変数に、ファイルやディレクトリのパスが代入されている。
// カレントディレクトリのファイル検索
void findDirectory()
{
WIN32_FIND_DATA fdFile = {0};
HANDLE hFind;
if((hFind = FindFirstFile(TEXT("*.*"),&fdFile)) != INVALID_HANDLE_VALUE)
{
do
{
if(fdFile.cFileName[0] != TEXT('.') || fdFile.cFileName[0] != TEXT('..'))
{
if(fdFile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{ // fdFile.cFileNameにディレクトリ名
}
else
{ // fdFile.cFileNameにファイル名
}
}
}while(FindNextFile(hFind, &fdFile));
FindClose(hFind);
}
}
ファイルの再帰検索
以下の例では、指定したディレクトリに存在する全てのファイルを再帰検索している。
// 関数内で自分自身を呼び出す再帰関数を作る
void CSampleView::SerchFiles(CString Path)
{
// ファイルの検索
CFileFind Finder;
Path += _T("\\*.*");
BOOL bWorking = Finder.FindFile(Path, 0);
while(bWorking)
{
bWorking = Finder.FindNextFile();
CString Getpath = Finder.GetFilePath();
CString Getname = Finder.GetFileName();
// 再帰的にディレクトリアイテムを作成
if(!(GetFileAttributes(Getpath) & FILE_ATTRIBUTE_DIRECTORY))
{ // ファイルの場合
}
else
{
if(Getname != _T(".") && Getname != _T(".."))
{ // ディレクトリの場合
SerchFiles(Getpath);
}
}
}
}
例えば、以下のようにSerchFilesメソッドを呼べば、次のようにDドライブの内容を全て書き出す。
SerchFiles(_T("D:\\"))