Windowsは、ファイルポインタを移動して単にEOFを設定したしようなファイルの場合に、 ファイルの書き込みが発生したタイミングで、ファイルの未使用領域を全て0で埋める動作をします。 なので、巨大なファイルを作成した場合、次のファイル書き込みの際に大量のセクタを0で埋める動作をする為に、 膨大な時間がかかる事となります。SetFileValidData関数であらかじめ有効なデータとして設定しておく事で、 Windowsがセクタを勝手に0で埋める事が無くなり、必要なデータだけを高速に書き込む事ができます。
#include <tchar.h> #include <iostream> #include <string> #include <windows.h> /* 特権設定する */ HRESULT EnablePrivilege ( TCHAR* wpPrivilegeName , BOOL bEnable ) { BOOL bRet; // トークンハンドル HANDLE hToken; /* プロセスに関連付けられているアクセストークンを開く */ bRet = ::OpenProcessToken( GetCurrentProcess() , 0 // | TOKEN_ASSIGN_PRIMARY // | TOKEN_DUPLICATE // | TOKEN_IMPERSONATE | TOKEN_QUERY // | TOKEN_QUERY_SOURCE | TOKEN_ADJUST_PRIVILEGES // | TOKEN_ADJUST_GROUPS // | TOKEN_ADJUST_DEFAULT // | TOKEN_ADJUST_SESSIONID , &hToken ); if ( 0 == bRet ) { // エラー return( ::HRESULT_FROM_WIN32( ::GetLastError() ) ); } // ローカル一意識別子 LUID tLuid; /* 指定されたシステムで使われているローカル一意識別子(LUID)を取得 */ bRet = LookupPrivilegeValue( NULL // システムを指定する文字列のアドレス , wpPrivilegeName // 特権を指定する文字列のアドレス , &tLuid // ローカル一意識別子のアドレス ); if ( 0 == bRet ) { // エラー DWORD dwLastError = ::GetLastError(); ::CloseHandle( hToken ); return( ::HRESULT_FROM_WIN32( dwLastError ) ); } TOKEN_PRIVILEGES tTokenPrivileges; tTokenPrivileges.PrivilegeCount = 1; tTokenPrivileges.Privileges[ 0 ].Luid = tLuid; tTokenPrivileges.Privileges[ 0 ].Attributes = ( FALSE != bEnable )? SE_PRIVILEGE_ENABLED : 0; /* 指定したアクセストークン内の特権を設定 */ bRet = ::AdjustTokenPrivileges( hToken , FALSE , &tTokenPrivileges , sizeof( tTokenPrivileges ) , NULL , NULL ); if ( 0 == bRet ) { // エラー DWORD dwLastError = ::GetLastError(); ::CloseHandle( hToken ); return( ::HRESULT_FROM_WIN32( dwLastError ) ); } // トークンハンドルを閉じる ::CloseHandle( hToken ); // 正常終了 return( S_OK ); } /* ファイル書き込み時に未使用領域を0埋めさせないようにする */ int _tmain ( int argc , _TCHAR* argv[] ) { // ロケール変更(wcoutでユニコードを出力する為) std::wcout.imbue(std::locale("", std::locale::ctype)); // 特権を有効にする( SE_MANAGE_VOLUME_NAME ) EnablePrivilege( SE_MANAGE_VOLUME_NAME, TRUE ); { // ファイルをオープン HANDLE hFile = CreateFile( L"TestLargeFile.bin" , GENERIC_WRITE , FILE_SHARE_READ , NULL , CREATE_NEW , FILE_ATTRIBUTE_NORMAL , NULL ); if ( hFile != INVALID_HANDLE_VALUE ) { // 作成するファイルのサイズ LONGLONG llFileSize = 0x0000000200000000; // ファイルポインタの移動 LONG lHigh = llFileSize >> 32; DWORD dwRet; // 8GB先までファイルポインタを進める LARGE_INTEGER pointer; pointer.QuadPart = llFileSize; SetFilePointerEx( hFile, pointer, NULL, FILE_BEGIN ) ; // EOFを設定 dwRet = ::SetEndOfFile( hFile ); // EOFの位置までを有効なデータとする dwRet = ::SetFileValidData( hFile, llFileSize ); // EOF - 3バイト手前の位置までファイルポインタを移動 pointer.QuadPart = llFileSize - 3; SetFilePointerEx( hFile, pointer, NULL, FILE_BEGIN ) ; // 3バイト書き込み DWORD dwTest = 0; WriteFile( hFile, "abc", 3, &dwTest, NULL ) ; std::wcout << L"3バイト書き込みました。" << std::endl; // ファイルのクローズ ::CloseHandle( hFile ); } } // 正常終了 return( 0 ); }
3バイト書き込みました。