わびさびサンプルソース

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

サブストリームも含めてファイルのコピーを行う

通常のファイルコピーではサブストリームをコピーすることはできません。管理者権限が必要 となりますが、BackupRead関数と、BackupWrite関数を使ってコピーするとサブストリームも含めて ファイルをコピーすることができます。

#include <stdio.h>
#include <tchar.h>
#include <iostream>
#include <windows.h>
#include <Shlobj.h>



/*
	サブストリームも含めてファイルのコピーを行う
*/
HRESULT BackupCopy
(
	  LPCWSTR pSrcFilePath	// コピー元ファイルパス
	, LPCWSTR pDstFilePath	// コピー先ファイルパス
)
{
	HRESULT hResult = S_OK;
	HANDLE hFileSrc = INVALID_HANDLE_VALUE;
	HANDLE hFileDst = INVALID_HANDLE_VALUE;

	// コピーバッファサイズ(10MB)
	DWORD dwBufferSize = 1024 * 1024 * 10;


	/*
		コピー用メモリの確保
	*/
	BYTE* bpCopyBuffer = (BYTE*)malloc( dwBufferSize );
	if ( NULL == bpCopyBuffer ) {

		// メモリ不足
		hResult = E_OUTOFMEMORY;
		goto err;
	}


	/*
		ファイルのオープン(読み込み側)
	*/
	hFileSrc = CreateFile(
			  pSrcFilePath
			, GENERIC_READ
			, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE
			, NULL
			, OPEN_EXISTING
			, FILE_FLAG_BACKUP_SEMANTICS
			, NULL
		);
	if ( INVALID_HANDLE_VALUE == hFileSrc ) {

		// エラー
		std::wcout << L"CreateFile(src) fail" << std::endl;
		hResult = ::HRESULT_FROM_WIN32( ::GetLastError() );
		goto err;
	}


	/*
		ファイルのオープン(書き込み側)
	*/
	hFileDst = CreateFile(
			  pDstFilePath
			, GENERIC_WRITE | WRITE_OWNER | WRITE_DAC
			, FILE_SHARE_READ
			, NULL
			, CREATE_ALWAYS
			, FILE_FLAG_BACKUP_SEMANTICS
			, NULL
		);
	if ( INVALID_HANDLE_VALUE == hFileDst ) {

		// エラー
		std::wcout << L"CreateFile(dst) fail" << std::endl;
		hResult = ::HRESULT_FROM_WIN32( ::GetLastError() );
		goto err;
	}


	/*
		ファイルのコピー
	*/
	{
		// BackupRead用コンテキスト保持ポインタ
		void* vpContextSrc = NULL;

		// BackupWrite用コンテキスト保持ポインタ
		void* vpContextDst = NULL;

		while( 1 ) {
			// 読み込んだバイト数
			DWORD dwNumberOfBytesRead = 0;

			/*
				ファイルの読み取り
			*/
			BOOL bRet = ::BackupRead(
					  hFileSrc				// ファイルハンドル
					, bpCopyBuffer			// 受け取りバッファ
					, dwBufferSize			// 読み取りバイト数
					, &dwNumberOfBytesRead	// 読み取ったバイト数
					, FALSE					// 終了タイプ
					, TRUE					// ACLを読み込むかどうか(TRUEを読み込む)
					, &vpContextSrc			// コンテキスト
				);
			if ( 0 == bRet ) {

				// エラー
				std::wcout << L"BackupRead fail" << std::endl;
				hResult = ::HRESULT_FROM_WIN32( ::GetLastError() );
				goto err;
			}

			// ストリームの終端だったか
			if ( NULL == vpContextDst && 0 == dwNumberOfBytesRead ) {

				// ファイルサイズ0だった。
				break;
			}


			/*
				ストリームの終端だったらContextを破棄して終了する
			*/
			if ( 0 == dwNumberOfBytesRead ) {

				// コンテキストの解放
				bRet = ::BackupWrite( hFileDst, NULL, 0, NULL, TRUE, FALSE, &vpContextDst );
				break;
			}


			// 書き込んだバイト数
			DWORD dwNumberOfWriteByte = 0;


			/*
				ファイルの書き込み
			*/
			bRet = ::BackupWrite(
					  hFileDst				// ファイルハンドル
					, bpCopyBuffer			// 書き込むデータ
					, dwNumberOfBytesRead	// 書き込むバイト数
					, &dwNumberOfWriteByte	// 書き込んだバイト数
					, FALSE					// 終了タイプ
					, TRUE					// ACLを書き込むか
					, &vpContextDst			// コンテキスト
				);
			if ( 0 == bRet ) {

				// エラー
				std::wcout << L"BackupWrite fail" << std::endl;
				hResult = ::HRESULT_FROM_WIN32( ::GetLastError() );
				goto err;
			}
		}
	}


err:
	// メモリの解放
	if ( NULL != bpCopyBuffer ) {
		::free( bpCopyBuffer );
	}

	// 読み込みファイルハンドルのクローズ
	if ( INVALID_HANDLE_VALUE != hFileSrc ) {
		::CloseHandle( hFileSrc );
	}

	// 書き込みファイルハンドルのクローズ
	if ( INVALID_HANDLE_VALUE != hFileDst ) {
		::CloseHandle( hFileDst );
	}

	// 処理結果を返す
	return( hResult );
}



/*
	BackupRead / BackupWriteでサブストリームも含めてファイルのコピーを行う
*/
int _tmain
(
	  int argc
	, _TCHAR* argv[]
)
{
	// std::wcoutのロケールを設定
	std::wcout.imbue( std::locale( "", std::locale::ctype ) );

	/*
		サブストリームも含めてファイルのコピーを行う
	*/
	HRESULT hResult = BackupCopy(
			  L"c:¥¥test¥¥test1.txt"	// コピー元ファイルパス
			, L"c:¥¥test¥¥test2.txt"	// コピー先ファイルパス
		);
	if ( S_OK == hResult ) {

		// コピー成功
		std::wcout << L"コピーできました。" << std::endl;
	}
	else {

		// コピー失敗
		std::wcout << L"コピーに失敗しました。" << std::endl;
	}

	// 正常終了
	return( 0 );
}

実行結果

コピーできました。






わびさびサンプルソース

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