わびさびサンプルソース

WindowsやHTML5などのプログラムのサンプルコードやフリーソフトを提供します。

ファイル書き込み時に未使用領域を0埋めさせないようにする

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バイト書き込みました。






わびさびサンプルソース

WindowsやHTML5などのプログラムのサンプルコードやフリーソフトを提供します。