Я пытаюсь переместить файл, используя SetFileInformationByHandle
. Этот метод был предложен Ниалом Дугласом в его разговоре CppCon2015 «Racing The File System» как способ атомарного перемещения/переименования файла. Однако я изо всех сил пытаюсь дать правильные аргументы; он всегда терпит неудачу и GetLastError
возвращает ERROR_INVALID_PARAMETER
.Перемещение файла с помощью SetFileInformationByHandle
Я попытался это с помощью следующих установок, с помощью Unicode Character Set:
- VS2015U1, запуск ехе под Windows 10
- VS2015U2, запуск ехе под управлением Windows Server 2012
- VS2013 , запуск exe под Windows 7
Но поведение такое же. Я обязательно получил доступ к тестовым папкам и тестовому файлу.
#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
? - Какие разрешения необходимы для ручек?
- Какова основная проблема
ERROR_INVALID_PARAMETER
отSetFileInformationByHandle
?
Те же проблемы, как [этот] (http://stackoverflow.com/questions/36217150/deleting-a-file-based-on-disk-id). –
@HansPassant Ну, у меня не возникло проблем с использованием файлов 'SetFileInformationByHandle' для * удаления *. Однако я не могу использовать его для * перемещения * файлов. Кроме того, я не использую 'OpenFileById'. Не могли бы вы быть более конкретными относительно того, что сходство между вопросом, которое у меня есть, и вопросами/ответами, с которыми вы связались? – dyp
Он ведет себя точно так же, удалите DELETE, чтобы увидеть это. Я предполагаю, что это особая проблема Win10, кто-то должен поговорить с MSFT об этом. Я буду добровольцем. –