2017-09-15 6 views
2

「MoreFilesX、FSExchangeObjectsCompat」には、「2つのファイル間でデータを交換する」という大きな機能がありました。これは通常、一時ファイルが書き出された後、FSExchangeObjectsCompatが呼び出されて、新しく保存された一時ファイルを古い「元の」ファイルと交換するセーフセーブアプローチの一環として使用されていました。Carbon FSExchangeObjectsCompatコールを実行するためのCocoaメソッドとは何ですか?

この機能は、HFS +ボリュームで失敗しなかったAPFSボリュームのHigh Sierraでエラーが発生しています。大きな驚きではありません。これらの呼び出しの多くは推奨されていません。

しかし、同じことをする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にあり、FSExchangeObjectsCompat()と同じ機能を実現するには、withItemAtURLと交換する必要があります。 – SMGreenfield

+0

'backupItemName'を指定することはオプションです。そのオプションやオプションを渡さないと、実装はあなたが探しているタイプの交換を行う可能性があります。 –

+0

将来参照するために、withItemAtURLの "new"ファイルは、replaceItemAtURLのファイルを置き換えた後、常にDELETEDです。 replaceItemAtURLの「元の」ファイルは、指定されている場合はbackupItemNameにコピーされ、NSFileManagerItemReplacementWithoutDeletingBackupItemオプションフラグが指定されていない限り削除されます。これは交換とまったく同じではありませんが、それは十分に近いようです。 10.12以上でrenamex_npを使用した場合やAPFSが存在する場合に、これが上位または優先であるかどうかは不明です。 – SMGreenfield

関連する問題