MFCの基礎 - ファイル

提供:MochiuWiki : SUSE, EC, PCB
ナビゲーションに移動 検索に移動

ファイルを開く

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, &lt1 );      // 作成日時
 FileTimeToLocalFileTime( &ft2, &lt2 );      // 最終アクセス日時
 FileTimeToLocalFileTime( &ft3, &lt3 );      // 最終更新日時
 
 // ローカル時刻からシステム日時に変換
 FileTimeToSystemTime( &lt1, &st1 );         // 作成日時
 FileTimeToSystemTime( &lt2, &st2 );         // 最終アクセス日時
 FileTimeToSystemTime( &lt3, &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, &lt1);         // 作成日時
 SystemTimeToFileTime(&st2, &lt2);         // 最終アクセス日時
 SystemTimeToFileTime(&st3, &lt3);         // 最終更新日時
 
 // ローカル時刻からファイル時刻に変換
 LocalFileTimeToFileTime(&lt1, &ft1);      // 作成日時
 LocalFileTimeToFileTime(&lt2, &ft2);      // 最終アクセス日時
 LocalFileTimeToFileTime(&lt3, &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:\\"))