通常のファイルコピーではサブストリームをコピーすることはできません。管理者権限が必要 となりますが、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 ); }
コピーできました。