【问题标题】:What is the Cocoa method for doing the Carbon FSExchangeObjectsCompat call?进行 Carbon FSExchangeObjectsCompat 调用的 Cocoa 方法是什么?
【发布时间】:2018-02-24 06:06:47
【问题描述】:

旧的 MoreFilesX 中有一个很棒的功能,即 FSExchangeObjectsCompat,“在两个文件之间交换数据”。它通常用作安全保存方法的一部分,其中写出临时文件,然后调用 FSExchangeObjectsCompat 以将新保存的临时文件与旧的“原始”文件交换。它保留了所有的元数据、权限等。

我发现此功能在 High Sierra 上的 APFS 卷上出现故障,而在 HFS+ 卷上从未出现过故障。不足为奇——其中许多调用已被弃用。

但是做同样事情的 Cocoa NSFileManager 方法是什么?

【问题讨论】:

    标签: macos cocoa nsfilemanager macos-carbon apfs


    【解决方案1】:

    【讨论】:

    • 要明确一点——虽然这是首选方法,但它实际上并没有用 withItemAtURL“交换”replaceItemAtURL。此操作后,原文件将在同一目录下的 backupItemName 下,然后需要与 withItemAtURL 交换以实现与 FSExchangeObjectsCompat() 相同的功能,对吧?
    • 提供backupItemName 是可选的。如果您不通过该选项或选项,则实施可能(并且很可能)进行您正在寻求的交换类型。
    • 供将来参考——withItemAtURL 中的“新”文件在替换replaceItemAtURL 中的文件后总是被删除。 replaceItemAtURL 处的“原始”文件将被复制到 backupItemName(如果提供),并且还将被删除,除非指定 NSFileManagerItemReplacementWithoutDeletingBackupItem 选项标志。所以这和交换并不完全一样,但似乎足够接近。不确定这是否优于或首选在 10.12 或更高版本或存在 APFS 时使用 renamex_np。
    【解决方案2】:

    您可以使用较低级别的函数执行类似的操作。这是我编写的用于 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;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-06-19
      • 1970-01-01
      • 2018-07-08
      • 2010-12-24
      • 2020-06-16
      • 2012-05-09
      相关资源
      最近更新 更多