在旧的MoreFilesX,FSExchangeObjectsCompat中有这个很棒的功能,"在两个文件之间交换数据"。它通常用作安全保存方法的一部分,其中写出临时文件,然后调用FSExchangeObjectsCompat以使用旧的"原始"来交换新保存的临时文件。文件。它保留了所有元数据,权限等。
我在APFS卷上的High Sierra看到了这个功能失败,这在HFS +卷上从未失败过。并不是一个大惊喜 - 许多电话都被弃用了。
但是做同样事情的Cocoa NSFileManager方法是什么?
答案 0 :(得分:2)
答案 1 :(得分:1)
您可以使用较低级别的功能执行类似操作。这是我编写的代码,用于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;
}