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