gpt4 book ai didi

c++ - 使用 SetFileInformationByHandle 移动文件

转载 作者:可可西里 更新时间:2023-11-01 13:23:36 30 4
gpt4 key购买 nike

我正在尝试使用 SetFileInformationByHandle 移动文件。 Niall Douglas 在他的 CppCon2015 演讲“Racing The File System”中提出了这项技术,作为一种自动移动/重命名文件的方法。但是,我正在努力提供正确的论据;它总是失败并且 GetLastError 返回 ERROR_INVALID_PARAMETER

我已经尝试过以下设置,使用 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 的根本问题是什么?

最佳答案

包含 FileRenameInfoFILE_RENAME_INFOSetFileInformationByHandle 文档包含一些错误。FILE_RENAME_INFO.FileNameLength 必须设置为复制到 FILE_RENAME_INFO.FileName 的字符数,不包括终止零,并且 FILE_RENAME_INFO.RootDirectory 必须为空,即使将文件从一个目录移动到另一个目录。

#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";
}

关于c++ - 使用 SetFileInformationByHandle 移动文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36450222/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com