하위 수준 기능을 사용하여 비슷한 작업을 수행 할 수 있습니다. 다음은 10.12 이전 SDK와 함께 사용하도록 작성한 코드입니다. 10.12 SDK 이상에서 컴파일하는 경우 다소 간단하게 만들 수 있으며 배포 대상이 10.12 이상이면 더 간단하게 만들 수 있습니다.
#ifndef RENAME_SWAP
#define RENAME_SWAP 0x00000002
#endif
/*!
@function ExchangeFiles
@abstract Given full paths to two files on the same volume,
swap their contents.
@discussion This is often part of a safe-save strategy.
@param inOldFile Full path to a file.
@param inNewFile Full path to a file.
@result 0 if all went well, -1 otherwise.
*/
int ExchangeFiles(const char* inOldFile, const char* inNewFile)
{
int result = -1;
static dispatch_once_t sOnce = 0;
static renameFuncType sRenameFunc = NULL;
// Try to get a function pointer to renamex_np, which is available in OS 10.12 and later.
dispatch_once(&sOnce,
^{
sRenameFunc = (renameFuncType) dlsym(RTLD_DEFAULT, "renamex_np");
});
// renamex_np is only available on OS 10.12 and later, and does not work on HFS+ volumes
// but does work on APFS volumes. Being the latest and greatest, we try it first.
if (sRenameFunc != NULL)
{
result = (*sRenameFunc)(inOldFile, inNewFile, RENAME_SWAP);
}
if (result != 0)
{
// exchangedata is an older function that works on HFS+ but not APFS.
result = exchangedata(inOldFile, inNewFile, 0);
}
if (result != 0)
{
// Neither function worked, we must go old school.
std::string nameTemplate(inOldFile);
nameTemplate += "-swapXXXX";
// Make a mutable copy of the template
std::vector<char> workPath(nameTemplate.size() + 1);
memcpy(&workPath[0], nameTemplate.c_str(), nameTemplate.size() + 1);
mktemp(&workPath[0]);
std::string tempPath(&workPath[0]);
// Make the old file have a temporary name
result = rename(inOldFile, tempPath.c_str());
// Put the new file data under the old name.
if (result == 0)
{
result = rename(inNewFile, inOldFile);
}
// Put the old data under the new name.
if (result == 0)
{
result = rename(tempPath.c_str(), inNewFile);
}
}
return result;
}
이것이 확실한 방법이지만 실제로 replaceItemAtURL을 withItemAtURL과 "교환"하는 것은 아닙니다. 이 작업을 수행 한 후 원본 파일은 동일한 디렉토리의 backupItemName에 저장되며 FSExchangeObjectsCompat()와 동일한 기능을 수행하려면 withItemAtURL과 교환해야합니다. – SMGreenfield
'backupItemName'을 제공하는 것은 선택 사항입니다. 해당 옵션이나 옵션을 전달하지 않으면 구현시 찾고있는 유형의 교환을 수행 할 수 있습니다. –
향후 참조를 위해 withItemAtURL의 "new"파일은 replaceItemAtURL에서 파일을 대체 한 후에 항상 삭제됩니다. replaceItemAtURL의 "원본"파일은 제공된 경우 backupItemName에 복사되며 NSFileManagerItemReplacementWithoutDeletingBackupItem 옵션 플래그가 지정되어 있지 않으면 삭제됩니다. 이것은 교환과 정확히 같지 않지만 충분히 가깝습니다. renamex_np를 10.12 이상으로 사용하거나 APFS가있을 때 이것이 더 우수하거나 선호되는지 확실하지 않습니다. – SMGreenfield