使用SetFileInformationByHandle移动文件
Moving a file using SetFileInformationByHandle
我正在尝试使用SetFileInformationByHandle
移动文件。Niall Douglas在其CppCon2015演讲"Racing The File System"中提出了这种技术,作为原子移动/重命名文件的一种方式。然而,我正在努力提供正确的论据;则总是失败并且CCD_ 2返回CCD_。
我已经用以下设置尝试过了,使用Unicode字符集:
- VS2015U1,在Windows 10下运行exe
- VS2015U2,在Windows Server 2012下运行exe
- VS2013,在Windows 7下运行exe
但行为是一样的。我确保可以访问测试文件夹和测试文件。
#include <sdkddkver.h>
#include <windows.h>
#include <cstring>
#include <iostream>
#include <memory>
int main()
{
auto const& filepath = L"C:\remove_tests\file.txt";
auto const& destpath = L"C:\remove_tests\other.txt";
// unclear if that's the "root directory"
auto const& rootdir = L"C:\remove_tests";
// handles will be leaked but that should be irrelevant here
auto const f_handle = CreateFile(filepath,
GENERIC_READ | GENERIC_WRITE | DELETE,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (f_handle == INVALID_HANDLE_VALUE)
{
auto const err = GetLastError();
std::cerr << "failed to create test file: " << err;
return err;
}
auto const parent_dir_handle = CreateFile(rootdir,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS,
NULL);
if (parent_dir_handle == INVALID_HANDLE_VALUE)
{
auto const err = GetLastError();
std::cerr << "failed to get handle to parent directory: " << err;
return err;
}
auto const destpath_bytes_with_null = sizeof(destpath);
// unclear if we need to subtract the one wchar_t of FileNameLength:
auto const struct_size = sizeof(FILE_RENAME_INFO) + destpath_bytes_with_null;
auto const buf = std::make_unique<char[]>(struct_size);
auto const fri = reinterpret_cast<FILE_RENAME_INFO*>(buf.get());
fri->ReplaceIfExists = TRUE; // as described by Niall Douglas
fri->RootDirectory = parent_dir_handle;
// with or without null terminator?
fri->FileNameLength = destpath_bytes_with_null;
std::memcpy(fri->FileName, destpath, destpath_bytes_with_null);
BOOL res = SetFileInformationByHandle(f_handle, FileRenameInfo,
fri, struct_size);
if (!res)
{
auto const err = GetLastError();
std::cerr << "failed to rename file: " << err;
return err;
}
else
std::cout << "success";
}
特别是,我的问题是:
FILE_RENAME_INFO
要求的"根目录"是什么- 句柄需要哪些权限
SetFileInformationByHandle
产生的ERROR_INVALID_PARAMETER
的根本问题是什么
带有FileRenameInfo
和FILE_RENAME_INFO
的SetFileInformationByHandle
文档包含一些错误。FILE_RENAME_INFO.FileNameLength
必须设置为复制到FILE_RENAME_INFO.FileName
的字符数(不包括终止零),并且即使将文件从一个目录移动到另一个目录,FILE_RENAME_INFO.RootDirectory
也必须为null。
#include <sdkddkver.h>
#include <windows.h>
#include <cstring>
#include <iostream>
#include <memory>
int _tmain( int argc, _TCHAR* argv [] )
{
wchar_t* filename = L"C:\remove_tests\file.txt";
wchar_t* destFilename = L"C:\remove_tests2\other.txt";
// handles will be leaked but that should be irrelevant here
auto fileHandle = CreateFile( filename,
GENERIC_READ | GENERIC_WRITE | DELETE,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL );
if ( fileHandle == INVALID_HANDLE_VALUE )
{
auto const err = GetLastError( );
std::cerr << "failed to create test file: " << err;
return err;
}
auto destFilenameLength = wcslen( destFilename );
auto bufferSize = sizeof( FILE_RENAME_INFO ) + ( destFilenameLength*sizeof( wchar_t ));
auto buffer = _alloca( bufferSize );
memset( buffer, 0, bufferSize );
auto const fri = reinterpret_cast<FILE_RENAME_INFO*>( buffer );
fri->ReplaceIfExists = TRUE;
fri->FileNameLength = destFilenameLength;
wmemcpy( fri->FileName, destFilename, destFilenameLength );
BOOL res = SetFileInformationByHandle( fileHandle, FileRenameInfo, fri, bufferSize );
if ( !res )
{
auto const err = GetLastError( );
std::cerr << "failed to rename file: " << err;
return err;
}
else
std::cout << "success";
}
我改变了几个想法:
1) 我不使用根句柄(我将其设置为NULL)
2) 我更改您的FILE_RENAME_INFO内存分配代码
注意:在windows 8中检查,在同一卷(磁盘)中移动文件
auto const& filepath = L"C:\remove_tests\file.txt";
auto const& destpath = L"C:\remove_tests\other.txt";
// unclear if that's the "root directory"
auto const& rootdir = L"C:\remove_tests";
// handles will be leaked but that should be irrelevant here
auto const f_handle = CreateFile(filepath,
GENERIC_READ | GENERIC_WRITE | DELETE,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (f_handle == INVALID_HANDLE_VALUE)
{
auto const err = GetLastError();
std::cerr << "failed to create test file: " << err;
return err;
}
/*auto const parent_dir_handle = CreateFile(rootdir,
GENERIC_READ | GENERIC_WRITE | DELETE,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS,
NULL);
if (parent_dir_handle == INVALID_HANDLE_VALUE)
{
auto const err = GetLastError();
std::cerr << "failed to get handle to parent directory: " << err;
return err;
}*/
auto const destpath_bytes_withOUT_null = _tcslen(destpath);
// unclear if we need to subtract the one wchar_t of FileNameLength:
auto const struct_size = sizeof(FILE_RENAME_INFO) + (destpath_bytes_withOUT_null + 1) * sizeof(WCHAR);
FILE_RENAME_INFO* fri = (FILE_RENAME_INFO*)new BYTE[struct_size];
fri->ReplaceIfExists = TRUE; // as described by Niall Douglas
fri->RootDirectory = NULL;//parent_dir_handle;
// with or without null terminator?
fri->FileNameLength = destpath_bytes_withOUT_null;// No include null
_tcscpy_s(fri->FileName, destpath_bytes_withOUT_null + 1, destpath);
BOOL res = SetFileInformationByHandle(f_handle, FileRenameInfo,
fri, struct_size);
delete fri;
if (!res)
{
auto const err = GetLastError();
std::cerr << "failed to rename file: " << err;
return err;
}
else
std::cout << "success";
相关文章:
- 如何在文件中向下移动?
- Windows C++:文件夹移动访问被拒绝错误
- 将内容从第一个文件("constituencies")移动到第二个文件("temp")并在之后重命名时,我的文件被删除
- 通过从文件中读取值来计算移动平均线
- 正在将助手函数移动到头文件
- 如何将文件移动到Qt中的另一个现有目录
- 如何在 c++ 中将数字从文件移动到数组中
- 将文件移动到其他目录
- 将可执行文件移动到 make 文件中的其他目录后运行可执行文件
- 使用WXWIDGET将多个文件移动到循环时
- 一些奇怪的行为:将文件夹中的所有文件移动到另一个位置
- 文件移动 - 操作系统如何知道是更新主文件表还是复制和删除
- Qmake Qt:将头文件移动到构建文件夹
- 将 QFile::copy 创建创建文件的副本或将内容从一个文件移动到另一个文件
- 如何使用C++(VS)将n个第一个文件移动到另一个目录
- 将清单文件移动到dll
- 使用make将.o文件移动到一个单独的目录
- 将内联方法从头文件移动到.cpp文件
- 自动将函数从头文件移动到cpp文件
- 在Linux中使用c++将文件移动到垃圾桶