2017-09-15 107 views
2

舊的MoreFilesX,FSExchangeObjectsCompat中有這樣一個功能,即「在兩個文件之間交換數據」。它通常用作安全保存方法的一部分,在該方法中寫入臨時文件,然後調用FSExchangeObjectsCompat將新保存的臨時文件與舊的「原始」文件進行交換。它保留了所有的元數據,特權等用於執行Carbon FSExchangeObjectsCompat調用的Cocoa方法是什麼?

我看到高Sierra上的這個函數在APFS捲上出現故障,這在HFS +捲上從未失敗。沒有什麼大驚喜 - 其中很多電話都被棄用了。

但是做同樣的事情的Cocoa NSFileManager方法是什麼?

回答

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; 
} 
2
+0

只是要清楚 - 雖然這是首選的方法,但它實際上並沒有將replaceItemAtURL與withItemAtURL「交換」。完成此操作後,原始文件將位於同一目錄下的backupItemName中,然後需要與withItemAtURL交換以實現與FSExchangeObjectsCompat()相同的功能,對吧? – SMGreenfield

+0

提供'backupItemName'是可選的。如果您沒有通過該選項或選項,那麼實施可能(並可能)執行您正在尋找的交易類型。 –

+0

爲了將來的參考 - withItemAtURL上的「new」文件在替換replaceItemAtURL處的文件後始終爲DELETED。 replaceItemAtURL中的「原始」文件將被複制到backupItemName(如果提供),並且也將被刪除,除非指定了NSFileManagerItemReplacementWithoutDeletingBackupItem選項標誌。所以這與交易所不完全相同,但似乎足夠接近。不確定這是優於還是偏好在10.12或更高版本上使用renamex_np或APFS存在時。 – SMGreenfield

相關問題