低水準機能を使用して同様のことを行うことができます。ここでは、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のファイルを置き換えた後、常にDELETEDです。 replaceItemAtURLの「元の」ファイルは、指定されている場合はbackupItemNameにコピーされ、NSFileManagerItemReplacementWithoutDeletingBackupItemオプションフラグが指定されていない限り削除されます。これは交換とまったく同じではありませんが、それは十分に近いようです。 10.12以上でrenamex_npを使用した場合やAPFSが存在する場合に、これが上位または優先であるかどうかは不明です。 – SMGreenfield